Audit events¶
Every organization and every developer account has an audit trail. This page describes what's in it and how to read it.
In the interactive reference
Both audit reads are now published in the OpenAPI document —
GET /api/v1/audit/organization/{organization_id} and
GET /api/v1/audit/developer/{developer_id}. The
interactive reference is authoritative for their
parameters and responses; this page explains what the trail contains
and how to read it. The CSV export is a web-app download built
from those same feeds, not an API operation, so it is not in the
schema and never will be.
Two trails¶
| Trail | Covers | Who can read it |
|---|---|---|
| Personal | Your own account: sign-ins, sign-outs, session activity, token lifecycle, email verification, security changes | You, and only you |
| Organization | Everything that happened in one organization | Organization Admin |
The personal trail follows you across every organization you belong to, which is why nobody else can read it — including your organization's admins, and including any token you own. Personal access tokens are refused on the personal trail for exactly that reason.
What a row contains¶
| Field | Meaning |
|---|---|
| Timestamp | When it happened, UTC |
| Event | What happened — Created, Revoked, Rolled back, Login succeeded, … |
| Type | What it happened to — Build, Release, Org membership, Webhook subscription, … |
| Identifier | Which specific thing |
| Actor | Who did it: a developer, a personal access token, a project access token, or the system |
| IP address | Where the request came from, where one applies |
| Details | Event-specific fields, humanised for display |
Rows are a verb plus a noun: "Created" + "Channel", "Revoked" + "Project access token", "Rolled back" + "Release". That pairing is deliberately small and composable rather than a sprawling list of dotted-string event names.
Secrets never appear. A row records that a token was created, rotated, or revoked; never the token.
The vocabulary¶
Events (the verb)¶
Lifecycle: Created · Edited · Deleted · Revoked · Rolled back · Accepted · Reinvited · Redundant action
Authentication and account security: Login succeeded · Login failed · Logged out · Session refreshed · Session revoked · All sessions revoked · Password changed · Email verified · Passkey registered · Passkey removed · Passkey login succeeded · MFA enabled · MFA disabled · MFA login succeeded · MFA recovery codes regenerated · Refresh token reuse detected
Tokens: Project access token created · rotated · revoked · deleted
Organization governance: Org MFA policy changed · Org SSO config changed · Org SSO domain verification changed · SSO login succeeded
Billing: Credited · Refunded · Credit forfeited · Prepaid enabled · Org card on file · Org spend cap changed · Org subscription created · Org payment state changed · Org lifecycle changed · Org tier changed
Builds and distribution: Build retention expired · Device registered · Store publish requested · Store publish completed · Store publish failed
Storage: Storage onboarding requested · Storage onboarding rejected · Storage onboarding withdrawn
Account data: Data export requested · completed · failed · downloaded · Account deletion requested · Account deletion cancelled
Types (the noun)¶
Developer · Organization · Project · Build · Channel · Release · Device · SDK app · Store connection · Webhook subscription · Storage backend · Tester group · Tester group member · Tester group grant · Org tester grant · Project tester grant · Channel tester grant · Channel tester invite · Org membership · Project membership · Org invite · Project invite · PAT · Project access token · Credit · Prepaid · Org spend cap · Org subscription · Org card on file · Org payment state · Org lifecycle · Org tier · Org MFA policy · Org SSO · Org SSO domain · Data export · Store publish · Storage onboarding request
Neither list is closed. New events and types are added over time, so treat an unfamiliar pairing as informational rather than an error.
Store publish completed will not appear in a feed today
The list above is the vocabulary the audit trail is defined against, not a list of what your feed contains. Store publishing is not operational, so a publish attempt records Store publish requested and then Store publish failed. Store publish completed is reserved for when publishing ships.
That is the same rule as the one above, in the other direction: handle the event you were given rather than assuming a request is eventually followed by a completion.
What is not recorded¶
- Tester downloads. They feed the download meter instead; on a popular release they would swamp everything else.
- Read-only API calls. The trail records changes and identity assertions, not every read.
- Artifact contents. AppGantry never inspects what's inside your build beyond the metadata it needs.
Reading the feed¶
In the web app¶
An organization's Audit page shows one UTC day at a time with a date picker and previous/next navigation. Your own Account → Audit page does the same for your personal trail.
Exporting¶
Both pages offer a CSV export over a date range. The export is produced by the web app, not by the API: the dashboard reads the same audit feeds documented below, turns the numeric event and data types into readable labels, and streams the result as a download. There is no REST operation for it, so there is nothing missing from the interactive reference — a CSV is not something the API serves.
The download has a header row and one row per event, with four columns:
| Column | What it holds |
|---|---|
timestamp |
When the event was recorded, in UTC |
event_type_label |
What happened, as a readable label (for example Login succeeded) |
data_type_label |
What kind of value the event carried, as a readable label |
ip_address |
The address the request came from, where one was recorded |
Labels rather than internal codes, so an export is readable without a lookup table. If you need the full structured detail of each event — including the identifiers the labels stand in for — read the API feeds described below and keep the JSON.
The export is subject to the same range caps as the feed it reads, and
sets the same X-Audit-Truncated header when a range is capped.
A browser download does not show you headers, so for a compliance
export take the range in smaller pieces, or read the feed over the API
where you can check the header.
Over the API¶
The audit feed is read either one UTC day at a time or over an
inclusive date range, and returns a JSON array — it is not
cursor-paginated. The organization feed requires organization Admin
and accepts a personal access token with READ scope bound to that
organization; the personal feed is self-only and requires an interactive
sign-in.
A large window can be truncated
Both query modes are capped: 1000 events for a single day and
5000 for a date range. When a query hits its cap the trail you
get back is incomplete, and the response says so with the
X-Audit-Truncated: true header. The header is absent when the
result is complete.
The body looks identical either way, so a client that never reads
the header cannot tell a complete export from a truncated one. See
Errors → Retry-After and other error headers.
The safe habit regardless: keep the window small. Read a day at a time for busy organizations, compare the row count against what you expected, and narrow the range and read again if a result looks suspiciously round or short. Treating a large-range read as complete is how rows go missing from a compliance export.
Both reads answer 500 when the audit store rejects the query, and
503 when it doesn't answer within the read timeout — the 503 carries
a Retry-After.
Retention¶
| Plan | Default audit retention |
|---|---|
| Team | 90 days |
| Business | 365 days |
| Enterprise | Not generally available |
Retention is a rolling window. If you need a longer record, export on a schedule that comfortably beats the window — monthly for Team, quarterly for Business — and keep the CSVs in your own systems.
Using the trail well¶
- Investigate access changes first. Org membership and Project membership rows with Created/Edited/Deleted answer "who gave them that?"
- Watch for
Refresh token reuse detected. It means a session token was replayed and the session family was cut. Once is a buggy client; repeatedly is worth investigating. - Correlate
Login failedbursts with the source IP column. - Reconcile token lifecycle — created, rotated, revoked — against the tokens you expect to exist.
- Export before you need it. The best time to discover your export works is not during an incident.
See also¶
- Audit & spend caps: the concept, and the spending side.
- Authorization: who can read what.
- Webhook events: near-real-time notifications, as opposed to the historical record.