Audit log
The append-only record of organisation-level change, what is captured, what is deliberately not, the entry shape, and how to page through it without misreading the totals.
Key rotations, invites, role changes, ownership transfers and sign-in attempts
are written to an append-only log scoped to the organisation. Admins can read
it from the dashboard or from GET /audit-logs.
The log answers “who changed this, and when”. It is deliberately not an event stream: writes are best-effort and a failure to record one never fails the action that triggered it, so the log is evidence rather than a control.
What is recorded
| Area | Actions |
|---|---|
| API keys | api_key.created, api_key.revoked |
| MCP | mcp.provisioned, mcp.trace_replayed |
| Members | member.invited, member.removed, member.role_changed, member.invitation_cancelled, member.ownership_transferred |
| Organisation | organization.created, organization.updated, organization.deleted |
| Apps | app.created, app.updated, app.deleted |
| Channels | channel.created, channel.updated, channel.deleted |
| Webhooks | webhook_endpoint.created, webhook_endpoint.deleted |
| Export destinations | export_destination.created, export_destination.updated, export_destination.deleted |
| Auth | auth.signup, auth.signin, auth.signin_failed, auth.google, auth.google_failed, auth.sso, auth.sso_failed, auth.org_setup, auth.token_refreshed |
| SSO | sso.connection_created, sso.connection_deleted, sso.enforcement_changed |
| User | user.profile_updated, user.updated_by_admin, user.active_org_switched |
| Billing | billing.subscription_changed, billing.subscription_status_changed, billing.subscription_event_failed |
| Operator | admin.plan_changed, admin.limits_overridden, admin.status_changed, admin.trial_changed, admin.org_disabled, admin.org_enabled, admin.user_disabled, admin.user_enabled, admin.billing_event_replayed, admin.access_request_reviewed, admin.access_request_approved |
The admin.* actions come from the operator panel, not from anything a member
of your organisation can do. They appear in your log when an operator acts on
your organisation, which is the point.
Environment changes are not audited. Creating, renaming, promoting or deleting an environment writes no entry. Neither do alert rules or moderation rules. Only the actions in the table above are captured. If your compliance story depends on covering one of those, say so, do not infer it from this page.
Entry shape
{
"id": "8f3c1a90-2b7e-4d51-9a06-7c3e1f5b2d84",
"organizationId": "org_01HZX9K2QF",
"actorId": "usr_01HZX9K3PA",
"action": "api_key.created",
"resourceType": "api_key",
"resourceId": "ak_live_9f2c…",
"metadata": {
"name": "prod deploy",
"environmentId": "env_01HZX9K4TC"
},
"ipAddress": "203.0.113.17",
"actor": {
"id": "usr_01HZX9K3PA",
"first_name": "Sayan",
"last_name": "Biswas",
"email": "sayan@example.com",
"username": "sayan"
},
"createdAt": "2026-08-21T18:03:11.742Z"
}Every identifier is a string. id is the entry’s UUID.
actorId and actor are null when no authenticated caller was responsible,
a failed sign-in has no actor, and neither does a system-triggered change.
actor is resolved by looking the user up at read time, so a removed user’s
entries keep their actorId but come back with actor: null.
metadata is action-specific and unvalidated. Do not build a schema on it; read
the fields you need defensively.
Querying
GET /audit-logs?page=1&limit=50
Authorization: Bearer <jwt>Requires the Admin role in the active organisation; anyone else gets 403.
The organisation comes from the caller’s session, not from a parameter, you
cannot read another organisation’s log by asking nicely.
Filters
| Parameter | Type | Default | Notes |
|---|---|---|---|
page | number | 1 | |
limit | number | 50 | |
action | string | Exact match, e.g. api_key.created. | |
resourceType | string | Exact match, e.g. api_key, channel. | |
actorId | string | The user who performed the action. | |
from | ISO 8601 | Inclusive lower bound on createdAt. | |
to | ISO 8601 | Inclusive upper bound on createdAt. |
from and to are the cheap filters: the log is stored partitioned by
organisation and sorted by createdAt, so a bounded range is a direct range
read. action, resourceType and actorId are applied as a post-filter over
that range, so narrowing the window first is what keeps a query fast.
Response
{
"data": [ /* newest first */ ],
"meta": {
"total": 1284,
"page": 1,
"limit": 50,
"totalPages": 26
}
}meta.total counts the entries the query has walked so far, not the size of
the log. Asking for page 1 walks roughly one page’s worth and reports that as
the total. The number converges on the truth as you page deeper, and is exact
only once you have reached the end. Use it to decide “is there more”, not to
render “1,284 events”.
Exporting a window
Page until a request returns fewer than limit rows, rather than trusting
totalPages:
page=1
while :; do
n=$(curl -sS \
"https://api.axonpush.xyz/audit-logs?from=2026-07-01&to=2026-08-01&limit=200&page=$page" \
-H "Authorization: Bearer $AXONPUSH_JWT" \
| tee "audit-$page.json" | jq '.data | length')
[ "$n" -lt 200 ] && break
page=$((page + 1))
doneGuarantees
- Append-only. There is no API to edit or delete an entry, and none of the write paths update one.
- Organisation-scoped. The read path derives the organisation from the caller. There is no cross-organisation query.
- Best-effort write. A failure to record is logged server-side and swallowed; the action it describes still succeeds. This keeps a logging outage from becoming an availability outage, and it means the log is not a transaction record.
- No expiry. Unlike events and traces, audit entries carry no TTL and are not aged out. The log grows for the life of the organisation.
Related
- Environments, not covered here, see the warning above
- Public ingest tokens, browser-safe tokens
- Organization, membership and ownership changes are recorded
Sentry DSN ingest
Point an existing Sentry SDK at axonpush by changing one environment variable, the envelope routes, how each item type is normalised, and the two things that will surprise you.
The dashboard
A tour of the axonpush dashboard and its pillars, from getting traffic in through the gateway to observing, alerting, moderating and governing what your agents do.