Skip to content

Audit Logs

GET https://api.bve.me/admin/audit-logs
Authorization: Bearer admin_bve_YOUR_ADMIN_KEY

Returns a paginated list of audit log entries. Every key lifecycle action (create, update, suspend, unsuspend, revoke, rotate, quota reset) is recorded as an audit log entry in D1.

ParameterTypeRequiredDefaultDescription
target_idstringNoFilter by the key UUID the action was taken on
actionstringNoFilter by exact action type (e.g., api_key.created, api_key.revoked, api_key.quota_reset)
action_categorystringNoFilter by action category: auth (login/logout events), keys (key lifecycle events), models (model allowlist events), or admins (admin user management events). Returns 400 validation_error for unrecognised values.
actor_typestringNoFilter by who performed the action. One of: admin (Bearer-token Admin API requests), admin_user (dashboard UI sessions). Returns 400 validation_error for other values.
target_typestringNoFilter by the type of resource the action targeted. One of: api_key, model, admin_user, model_allowlist. Returns 400 validation_error for other values.
searchstringNoFree-text substring search across action, target_id, and actor_type fields (SQL LIKE match). Case-insensitive on most SQLite builds.
sincestringNoReturn only entries at or after this ISO 8601 timestamp (e.g., 2026-05-01T00:00:00Z). Passing an invalid timestamp returns 400 validation_error.
untilstringNoReturn only entries at or before this ISO 8601 timestamp. Combine with since for a precise date range. Passing an invalid timestamp returns 400 validation_error.
limitintegerNo100Max entries to return (1–500)
offsetintegerNo0Number of entries to skip. Use with ?limit= for cursor-free pagination.
{
"total": 87,
"has_more": true,
"logs": [
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"action": "api_key.created",
"actor_type": "admin",
"target_type": "api_key",
"target_id": "550e8400-e29b-41d4-a716-446655440000",
"metadata": { "name": "my-client", "source": "legacy_admin_api" },
"created_at": "2026-05-21T12:00:00.000Z"
},
{
"id": "880e8400-e29b-41d4-a716-446655440003",
"action": "api_key.updated",
"actor_type": "admin",
"target_type": "api_key",
"target_id": "550e8400-e29b-41d4-a716-446655440000",
"metadata": {
"changes": ["name", "rpm_limit"],
"before": { "name": "old-name", "rpm_limit": 60 },
"after": { "name": "new-name", "rpm_limit": 120 },
"source": "legacy_admin_api"
},
"created_at": "2026-05-21T13:00:00.000Z"
}
]
}
FieldTypeDescription
totalintegerTotal number of audit log entries matching the current filters (ignores limit/offset). Use for pagination UI.
has_morebooleantrue when offset + len(logs) < total — indicates another page of results exists.
logsarrayArray of audit log entry objects (see below).
FieldTypeDescription
idstringUUID of the audit log entry
actionstringAction type (see below)
actor_typestring"admin" for Bearer-token Admin API operations; "admin_user" for dashboard actions
target_typestring"api_key" for key events; "admin_user" for admin user events; "model_allowlist" for allowlist events
target_idstringUUID or identifier of the affected resource (key UUID, admin user UUID, or model name)
metadataobject | nullParsed JSON with action-specific details (e.g., name, limits)
created_atstringISO 8601 timestamp

Audit log entries are grouped into four categories. The action_category filter matches the category heading, while ?action=<exact_action> matches a specific row.

keys — API key lifecycle (action_category=keys)

Section titled “keys — API key lifecycle (action_category=keys)”
ActionTriggeractor_typemetadata fields
api_key.createdPOST /admin/api-keysadminname
api_key.updatedPATCH /admin/api-keys/:idadminchanges — array of changed field names (e.g. ["rpm_limit", "name"]); before — object with old values keyed by snake_case field name; after — object with new values keyed by snake_case field name
api_key.rotatedPOST /admin/api-keys/:id/rotateadmin(none)
api_key.suspendedPOST /admin/api-keys/:id/suspendadmin(none)
api_key.unsuspendedPOST /admin/api-keys/:id/unsuspendadmin(none)
api_key.revokedPOST /admin/api-keys/:id/revokeadmin(none)
api_key.quota_resetPOST /admin/api-keys/:id/reset-quotaadminwindow — one of minute, day, month, all
api_key.bulk_revokedDashboard bulk revokeadmin_useractorId, actorEmail, ids (array of revoked UUIDs), count
api_key.bulk_suspendedDashboard bulk suspendadmin_useractorId, actorEmail, ids (array of suspended UUIDs), count
api_key.bulk_unsuspendedDashboard bulk unsuspendadmin_useractorId, actorEmail, ids (array of unsuspended UUIDs), count

Single-key lifecycle entries triggered via the Bearer-token Admin API include source: "legacy_admin_api" in metadata. Bulk operation entries do not — they are always dashboard-initiated.

auth — Admin dashboard login events (action_category=auth)

Section titled “auth — Admin dashboard login events (action_category=auth)”
ActionTriggermetadata fields
admin.loginSuccessful dashboard loginactorEmail, ipAddress
admin.logoutDashboard logoutactorEmail

models — Model allowlist changes (action_category=models)

Section titled “models — Model allowlist changes (action_category=models)”

Actions in this category are generated by two paths — the Bearer-token Admin API and the dashboard UI — and use different action strings and actor_type values.

Admin API (actor_type: "admin"):

ActionTriggermetadata fields
model_allowlist.addedPOST /admin/model-allowlist — new model entryenabled
model_allowlist.updatedPOST /admin/model-allowlist — existing model entry toggledenabled
model_allowlist.removedDELETE /admin/model-allowlist/:modelenabled (value at time of deletion)

Dashboard (actor_type: "admin_user"):

ActionTriggermetadata fields
model_allowlist.updateModel entry created or toggled via dashboard UIactorId, actorEmail, enabled
model_allowlist.deleteModel entry removed via dashboard UIactorId, actorEmail

To retrieve all model allowlist changes regardless of source, use ?action_category=models. To isolate Admin API changes, add ?action=model_allowlist.added or ?action=model_allowlist.removed. To isolate dashboard changes, use ?action=model_allowlist.update.

admins — Admin user management (action_category=admins)

Section titled “admins — Admin user management (action_category=admins)”
ActionTriggermetadata fields
admin_user.createNew dashboard user createdactorId, actorEmail, email (new user’s email)
admin_user.updateDashboard user role or details changedactorId, actorEmail
admin_user.deleteDashboard user deletedactorId, actorEmail
admin_user.password_changedDashboard user changed their own passwordactorId, actorEmail
Terminal window
curl "https://api.bve.me/admin/audit-logs" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
Terminal window
curl "https://api.bve.me/admin/audit-logs?target_id=550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
Terminal window
curl "https://api.bve.me/admin/audit-logs?action=api_key.rotated" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

Use ?action_category= to match a group of related actions without listing each one individually:

Terminal window
# All key lifecycle events (create/update/suspend/unsuspend/revoke/rotate/quota_reset)
curl "https://api.bve.me/admin/audit-logs?action_category=keys" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Auth events only (login, logout)
curl "https://api.bve.me/admin/audit-logs?action_category=auth" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Model allowlist events only
curl "https://api.bve.me/admin/audit-logs?action_category=models" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Admin user management events (create, update, delete, password change)
curl "https://api.bve.me/admin/audit-logs?action_category=admins" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Key lifecycle events for a specific key
curl "https://api.bve.me/admin/audit-logs?action_category=keys&target_id=550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

Use ?actor_type= to isolate events by who triggered them — the Bearer-token Admin API (admin) or the dashboard UI (admin_user):

Terminal window
# Only events triggered via the Bearer-token Admin API
curl "https://api.bve.me/admin/audit-logs?actor_type=admin" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Only events triggered via the dashboard UI (human operator or session-based action)
curl "https://api.bve.me/admin/audit-logs?actor_type=admin_user" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

Use ?target_type= to restrict results to a specific resource category:

Terminal window
# Only events that affected API keys
curl "https://api.bve.me/admin/audit-logs?target_type=api_key" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Only events that affected the model allowlist
curl "https://api.bve.me/admin/audit-logs?target_type=model_allowlist" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Dashboard-initiated admin user events
curl "https://api.bve.me/admin/audit-logs?target_type=admin_user&actor_type=admin_user" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

Use ?search= to match a substring across action, target_id, and actor_type fields:

Terminal window
# All entries containing "rotated"
curl "https://api.bve.me/admin/audit-logs?search=rotated" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Combine with since/until for a bounded search window
curl "https://api.bve.me/admin/audit-logs?search=revoked&since=2026-05-01T00:00:00Z" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
Terminal window
curl "https://api.bve.me/admin/audit-logs?since=2026-05-01T00:00:00Z" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

Combine since and until to query a bounded time window:

Terminal window
curl "https://api.bve.me/admin/audit-logs?since=2026-05-01T00:00:00Z&until=2026-05-31T23:59:59Z" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
Terminal window
curl "https://api.bve.me/admin/audit-logs?limit=10" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

Use ?limit= and ?offset= together for cursor-free pagination:

Terminal window
# Page 1 — first 50 entries
curl "https://api.bve.me/admin/audit-logs?limit=50&offset=0" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Page 2 — next 50 entries
curl "https://api.bve.me/admin/audit-logs?limit=50&offset=50" \
-H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"

bun run audit-logs wraps this endpoint with all server-side filters and human-readable output.

Terminal window
# All recent events (local dev server)
bun run audit-logs
# Production
bun run audit-logs -- --remote
# Filter by date range
bun run audit-logs -- --since 2026-01-01 --until 2026-05-31
# Filter by action category
bun run audit-logs -- --action-category keys # key lifecycle events
bun run audit-logs -- --action-category auth # login/logout events
# Filter by exact action
bun run audit-logs -- --action api_key.rotated
# Filter by actor type
bun run audit-logs -- --actor-type admin_user # dashboard sessions
# Filter by target resource
bun run audit-logs -- --target-type api_key --target-id <uuid>
# Text search
bun run audit-logs -- --search "revoked"
# Paginate
bun run audit-logs -- --limit 50 --offset 100
# Machine-readable JSON
bun run audit-logs -- --json
StatusCodeCause
400validation_erroraction_category is not one of auth, keys, models, admins
400validation_erroractor_type is not one of admin, admin_user
400validation_errortarget_type is not one of api_key, model, admin_user, model_allowlist
400validation_errorsince or until is not a parseable ISO 8601 timestamp
401missing_api_keyNo Authorization header
401invalid_api_keyAdmin key does not match the configured ADMIN_API_KEY secret
  • Audit log entries are immutable. They cannot be deleted or modified via the API.
  • Entries are returned in descending chronological order (most recent first).
  • Rate limit events are not in this log. They are sent to the EVENTS_QUEUE as type: "alert" events and optionally delivered to a configured WEBHOOK_URL.