Audit Logs
Spanlens records every significant action within your organization. Track who changed what and when, API key creation, provider key additions, member invitations, role changes, and plan switches. View the log directly in Settings → Audit log or query it via the REST API to feed into an external SIEM or compliance tool.
Use cases
- Security audits. Determine which keys a departing employee created, or whether admin roles changed at an unexpected time.
- Compliance. Satisfy SOC 2, ISO 27001, and similar audit requirements that ask for a change access log on demand.
- Incident investigation. If the proxy starts returning auth errors, check the audit log for provider key rotations around that time.
Recorded events
Twenty-four distinct actions are emitted across thirteen mutation routes. Severity in the dashboard is inferred from the verb (.delete / .rotate / billing.* / workspace.* are HIGH, .create / .update / .invite are MED, the rest are LOW). Every row carries the actor user id and IP address pulled from x-forwarded-for / x-real-ip / cf-connecting-ip.
| Resource | Actions |
|---|---|
| Spanlens key | api_key.create · api_key.enable · api_key.disable · api_key.delete |
| Provider key | provider_key.add · provider_key.update · provider_key.rotate · provider_key.delete |
| Prompt version | prompt_version.create · prompt_version.rollback · prompt_version.delete |
| A/B experiment | ab_experiment.start · ab_experiment.update · ab_experiment.conclude · ab_experiment.stop · ab_experiment.delete |
| Members | member.invite · member.invite_accept · member.invite_cancel · member.role_change · member.remove |
| Workspace | workspace.rename · workspace.security_update · workspace.branding_update · workspace.overage_update |
| Billing | billing.checkout_create · billing.cancel |
| Project | project.create · project.update · project.delete |
| Alert / channel | alert.create · alert.update · alert.delete · notification_channel.create · notification_channel.delete |
| Webhook | webhook.create · webhook.update · webhook.delete |
| Pending deletion queue | pending_deletion.restore |
View the log in Settings → Audit log (admin-only full viewer with time-window + action filters, paginated 50 per page, click any row to open a drawer with the metadata JSON, IP, and actor UUID). Editors and viewers see the abbreviated table on the same Settings tab. Programmatic consumers should hit the REST API below.
API reference
List logs
GET /api/v1/audit-logs?limit=50&offset=0
# Filter by action
GET /api/v1/audit-logs?limit=50&offset=0&action=api_key.create
# Filter by user
GET /api/v1/audit-logs?limit=50&offset=0&user_id=<uuid>
# Filter by inclusive time range (ISO 8601)
GET /api/v1/audit-logs?from=2026-05-01T00:00:00Z&to=2026-05-31T23:59:59Z
# List the distinct action values seen on this workspace
# (powers the filter dropdown; capped at the last 1000 rows)
GET /api/v1/audit-logs/actionsbashQuery parameters
| Parameter | Default | Description |
|---|---|---|
limit | 50 | Results per page. Maximum 200. |
offset | 0 | Pagination offset. |
action | (all) | Filter to a specific action value, e.g. member.invite. |
user_id | (all) | Show only actions performed by a specific user (UUID). |
from | (no lower bound) | Inclusive lower bound on created_at, ISO 8601 timestamp. Malformed values return 400. |
to | (no upper bound) | Inclusive upper bound on created_at, ISO 8601 timestamp. |
Response example
{
"data": [
{
"id": "al_01j9abc...",
"action": "api_key.create",
"resource_type": "api_key",
"resource_id": "key_01j9...",
"user_id": "usr_01j9...",
"metadata": {
"key_name": "Production proxy key"
},
"ip_address": "203.0.113.42",
"created_at": "2026-05-15T08:30:00Z"
},
{
"id": "al_01j9def...",
"action": "member.role_change",
"resource_type": "org_member",
"resource_id": "usr_01j9yyy...",
"user_id": "usr_01j9xxx...",
"metadata": {
"from_role": "viewer",
"to_role": "editor",
"target_email": "colleague@example.com"
},
"ip_address": "198.51.100.7",
"created_at": "2026-05-15T07:12:45Z"
}
],
"total": 142,
"limit": 50,
"offset": 0
}jsonResponse fields
| Field | Type | Description |
|---|---|---|
id | string | Unique log entry ID |
action | string | Action performed (see event table above) |
resource_type | string | Type of resource changed (e.g. api_key, org_member) |
resource_id | string | ID of the changed resource |
user_id | string | ID of the user who performed the action |
metadata | object | Event-specific detail (before/after values, target email, etc.) |
ip_address | string | IP address of the request |
created_at | string (ISO 8601) | When the event occurred (UTC) |
curl examples
# Fetch the 20 most recent entries
curl "https://server.spanlens.io/api/v1/audit-logs?limit=20" \
-H "Authorization: Bearer <JWT>"
# Filter to provider key events only
curl "https://server.spanlens.io/api/v1/audit-logs?action=provider_key.add&limit=50" \
-H "Authorization: Bearer <JWT>"
# Second page (entries 51–100)
curl "https://server.spanlens.io/api/v1/audit-logs?limit=50&offset=50" \
-H "Authorization: Bearer <JWT>"bashLimitations
- Admin-only access. Only organization members with the admin role can query audit logs. Editors and viewers are blocked in both the API and the dashboard.
- 200 rows per page maximum. Passing a
limitabove 200 returns a 400 error. - Fixed sort order. Results are always returned in
created_at DESCorder. Sort direction cannot be changed. - Retention. Audit logs are retained for the lifetime of your account and are not currently pruned on a fixed schedule. If you need a guaranteed retention window for compliance reasons, export the log periodically via the API and store it in your own system; a future release may introduce per-plan retention windows, at which point this page and the Privacy Policy will be updated together.
- Proxy requests are not recorded here. LLM request and response history is in Requests and Traces. Audit logs focus on organization configuration changes.
Related: Members & Invitations, Security (PII / prompt injection scanning), Webhooks (HTTP event delivery). Dashboard: Settings → Audit log.