Audit Logs
Notifica maintains comprehensive audit logs for all sensitive operations performed on your account. Audit logs help you maintain compliance, debug issues, and monitor security events.
Overview
Every API key operation, team member change, subscription modification, domain configuration, and webhook change is automatically logged with:
- Who performed the action (user, API key, or system)
- What action was performed
- When it happened (with microsecond precision)
- Which resource was affected
- Where the request came from (IP address, user agent)
- Additional context (metadata specific to the action)
Audit logs are immutable — once created, they cannot be modified or deleted. They are retained indefinitely for compliance purposes.
Tracked Events
API Keys
| Event | Description | Metadata |
|---|---|---|
api_key.created | A new API key was generated | environment, key_type, scopes |
api_key.revoked | An API key was revoked | key_prefix, revoked_reason |
api_key.rotated | An API key was rotated with a grace period | old_key_prefix, new_key_prefix, grace_period_hours |
Team Members
| Event | Description | Metadata |
|---|---|---|
team_member.invited | A new team member was invited to the workspace | email, role |
team_member.removed | A team member was removed from the workspace | email, role |
team_member.role_changed | A team member's role or permissions were changed | old_role, new_role |
Subscriptions
| Event | Description | Metadata |
|---|---|---|
subscription.created | A new subscription was created | plan_id, gateway |
subscription.plan_changed | Plan was upgraded or downgraded | old_plan_id, new_plan_id, change_type |
subscription.cancelled | Subscription was cancelled | reason, cancel_at_period_end |
subscription.payment_failed | A payment attempt failed | invoice_id, invoice_number, amount_cents, reason |
subscription.expired | Subscription expired after grace period | reason, days_overdue |
Domains
| Event | Description | Metadata |
|---|---|---|
domain.added | A new sending domain was registered | domain, status |
domain.verified | Domain verification succeeded via DNS check | domain, dkim_verified |
domain.removed | A sending domain was deleted | domain, was_verified |
Webhooks
| Event | Description | Metadata |
|---|---|---|
webhook.created | A new webhook endpoint was configured | url, events |
webhook.updated | Webhook configuration was modified | url, events, active |
webhook.deleted | A webhook endpoint was removed | url |
API Reference
List Audit Logs
Retrieve audit logs for a tenant with optional filtering.
GET /api/internal/audit-logs
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
tenant_id | string | Yes | Filter logs by tenant ID |
action | string | No | Filter by specific action (e.g., api_key.created) |
resource_type | string | No | Filter by resource type (e.g., api_key, team_member) |
actor_type | string | No | Filter by actor type: user, system, or api_key |
limit | integer | No | Number of records to return (default: 50, max: 200) |
Example Request
curl -X GET "https://api.notifica.app/api/internal/audit-logs?tenant_id=abc123&action=api_key.created&limit=10" \
-H "Authorization: Bearer your-admin-token"
Example Response
{
"audit_logs": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "abc123",
"actor_id": "def456",
"actor_type": "user",
"action": "api_key.created",
"resource_type": "api_key",
"resource_id": "789xyz",
"metadata": {
"environment": "production",
"key_type": "publishable",
"scopes": ["notifications:send"]
},
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
"inserted_at": "2026-02-12T10:30:45.123456Z"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"tenant_id": "abc123",
"actor_id": null,
"actor_type": "system",
"action": "subscription.payment_failed",
"resource_type": "subscription",
"resource_id": "sub_abc123",
"metadata": {
"invoice_id": "inv_xyz789",
"invoice_number": "INV-2026-001",
"amount_cents": 9900,
"reason": "card_declined"
},
"ip_address": null,
"user_agent": null,
"inserted_at": "2026-02-12T08:15:22.987654Z"
}
],
"count": 2
}
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique audit log entry ID |
tenant_id | string | Tenant the action was performed on |
actor_id | string | null | ID of the actor (user, API key, or null for system) |
actor_type | string | Type of actor: user, api_key, or system |
action | string | The action that was performed (see event tables above) |
resource_type | string | Type of resource affected (e.g., api_key, team_member) |
resource_id | string | null | ID of the affected resource |
metadata | object | Additional context specific to the action |
ip_address | string | null | IP address of the requester (null for system actions) |
user_agent | string | null | User agent of the requester (null for system actions) |
inserted_at | string | ISO 8601 timestamp when the log was created |
Actor Types
Audit logs record three types of actors:
user— A dashboard user (team member) performing an action through the web UIapi_key— An API key used to make a programmatic requestsystem— Automated system actions (e.g., subscription expiration, payment failures)
Retention Policy
Audit logs are retained indefinitely to support compliance requirements (LGPD, GDPR, SOC 2). They cannot be deleted except as part of a full account deletion request.
If you require audit log exports for compliance or archival purposes, contact support.
Use Cases
Compliance & Security
- LGPD/GDPR compliance: Track all access to personal data and demonstrate accountability
- Security audits: Monitor API key creation, rotation, and revocation
- Access reviews: Verify who has access to your workspace and when permissions changed
Debugging & Troubleshooting
- Payment failures: Identify when and why subscription payments failed
- Domain verification issues: Track domain registration and verification attempts
- Webhook debugging: See when webhook configurations were changed
Operational Monitoring
- Team changes: Monitor when team members are added, removed, or role changes occur
- Subscription lifecycle: Track plan changes, cancellations, and reactivations
- API usage patterns: Analyze API key usage by examining audit logs
SDK Examples
Audit logs are accessible via all official Notifica SDKs. Note that audit log access requires admin authentication (bearer token from backoffice login), not regular API keys.
Node.js
import { NotificaAdmin } from '@notifica/node';
const admin = new NotificaAdmin({
token: process.env.NOTIFICA_ADMIN_TOKEN,
});
// List audit logs with filters
const { auditLogs } = await admin.auditLogs.list({
tenantId: 'your-tenant-id',
action: 'api_key.created',
limit: 50,
});
for (const log of auditLogs) {
console.log(`${log.insertedAt} | ${log.actorType} | ${log.action}`);
}
// Filter by resource type
const apiKeyLogs = await admin.auditLogs.list({
tenantId: 'your-tenant-id',
resourceType: 'api_key',
});
Python
from notifica import NotificaAdmin
admin = NotificaAdmin(token="your-admin-token")
# List audit logs
audit_logs = admin.audit_logs.list(
tenant_id="your-tenant-id",
action="api_key.created",
limit=50
)
for log in audit_logs:
print(f"{log.inserted_at} | {log.actor_type} | {log.action}")
# Filter by date range
recent_logs = admin.audit_logs.list(
tenant_id="your-tenant-id",
actor_type="user",
limit=100
)
Go
package main
import (
"context"
"fmt"
"github.com/notifica-tech/notifica-go"
)
func main() {
client := notifica.NewAdminClient("your-admin-token")
logs, err := client.AuditLogs.List(context.Background(), ¬ifica.AuditLogListParams{
TenantID: "your-tenant-id",
Action: notifica.String("api_key.created"),
ResourceType: notifica.String("api_key"),
Limit: notifica.Int(50),
})
if err != nil {
panic(err)
}
for _, log := range logs.AuditLogs {
fmt.Printf("%s | %s | %s\n", log.InsertedAt, log.ActorType, log.Action)
}
}
Java
import com.notifica.NotificaAdmin;
import com.notifica.model.AuditLog;
import com.notifica.param.AuditLogListParams;
NotificaAdmin admin = NotificaAdmin.builder()
.token("your-admin-token")
.build();
AuditLogListParams params = AuditLogListParams.builder()
.tenantId("your-tenant-id")
.action("api_key.created")
.limit(50L)
.build();
List<AuditLog> logs = admin.auditLogs().list(params).getAuditLogs();
for (AuditLog log : logs) {
System.out.printf("%s | %s | %s%n",
log.getInsertedAt(), log.getActorType(), log.getAction());
}
Raw API Examples
If you're not using an SDK, you can access audit logs directly via HTTP:
Export Recent Audit Logs
import requests
API_URL = "https://app.usenotifica.com.br/api/internal/audit-logs"
ADMIN_TOKEN = "your-admin-token"
TENANT_ID = "your-tenant-id"
response = requests.get(
API_URL,
params={"tenant_id": TENANT_ID, "limit": 100},
headers={"Authorization": f"Bearer {ADMIN_TOKEN}"}
)
audit_logs = response.json()["audit_logs"]
print(f"Retrieved {len(audit_logs)} audit log entries")
for log in audit_logs:
print(f"{log['inserted_at']} | {log['actor_type']} | {log['action']}")
Monitor Critical Actions
const axios = require('axios');
const CRITICAL_ACTIONS = [
'api_key.revoked',
'team_member.removed',
'subscription.cancelled',
'domain.removed',
'webhook.deleted'
];
async function checkCriticalActions(tenantId) {
const response = await axios.get('https://app.usenotifica.com.br/api/internal/audit-logs', {
params: { tenant_id: tenantId, limit: 50 },
headers: { Authorization: `Bearer ${process.env.ADMIN_TOKEN}` }
});
const criticalLogs = response.data.audit_logs.filter(log =>
CRITICAL_ACTIONS.includes(log.action)
);
if (criticalLogs.length > 0) {
console.warn(`⚠️ Found ${criticalLogs.length} critical actions:`);
criticalLogs.forEach(log => {
console.warn(` - ${log.action} by ${log.actor_type} at ${log.inserted_at}`);
});
}
}
Best Practices
- Regular Reviews: Review audit logs weekly to catch unauthorized changes
- Alerting: Set up automated alerts for critical actions (key revocation, member removal)
- Compliance: Export and archive audit logs quarterly for compliance documentation
- Investigation: When investigating issues, filter by
resource_idto trace a specific resource's history - Team Awareness: Share audit log access with your security and compliance teams