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.

ResourceActions
Spanlens keyapi_key.create · api_key.enable · api_key.disable · api_key.delete
Provider keyprovider_key.add · provider_key.update · provider_key.rotate · provider_key.delete
Prompt versionprompt_version.create · prompt_version.rollback · prompt_version.delete
A/B experimentab_experiment.start · ab_experiment.update · ab_experiment.conclude · ab_experiment.stop · ab_experiment.delete
Membersmember.invite · member.invite_accept · member.invite_cancel · member.role_change · member.remove
Workspaceworkspace.rename · workspace.security_update · workspace.branding_update · workspace.overage_update
Billingbilling.checkout_create · billing.cancel
Projectproject.create · project.update · project.delete
Alert / channelalert.create · alert.update · alert.delete · notification_channel.create · notification_channel.delete
Webhookwebhook.create · webhook.update · webhook.delete
Pending deletion queuepending_deletion.restore

View the log in SettingsAudit 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/actions
bash

Query parameters

ParameterDefaultDescription
limit50Results per page. Maximum 200.
offset0Pagination 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
}
json

Response fields

FieldTypeDescription
idstringUnique log entry ID
actionstringAction performed (see event table above)
resource_typestringType of resource changed (e.g. api_key, org_member)
resource_idstringID of the changed resource
user_idstringID of the user who performed the action
metadataobjectEvent-specific detail (before/after values, target email, etc.)
ip_addressstringIP address of the request
created_atstring (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>"
bash

Limitations

  • 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 limit above 200 returns a 400 error.
  • Fixed sort order. Results are always returned in created_at DESC order. 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.