Skip to content

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

  1. Investigate access changes first. Org membership and Project membership rows with Created/Edited/Deleted answer "who gave them that?"
  2. 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.
  3. Correlate Login failed bursts with the source IP column.
  4. Reconcile token lifecycle — created, rotated, revoked — against the tokens you expect to exist.
  5. Export before you need it. The best time to discover your export works is not during an incident.

See also