Audit log
From django-crm 1.11.0 an org's admins can read its security audit log: who signed in and from where, and what the server refused or changed on its own. It is read-only. Nobody can edit or delete an entry from the app.
Where to find it
- Web app: Settings → Audit log (
/settings/audit-log). - Phone app: Settings → Audit log.
- API:
GET /api/org/audit-log/.
It is for admins only. A member gets 403, and the settings menu on either client does not
offer it to them.
What it records
The entries are the security events the server writes against your org, among them:
- Sign-ins, sign-outs and switches between organizations
- Token refreshes and revocations
- Some refused actions
- Clearing a vertical pack's sample data
- Webhooks: Webhook Paused when the admin who owned it lost that standing, Webhook Re-enabled when an admin turns one back on, and Webhook Destination Changed when an admin changes its URL, events or format or rotates its secret (see Webhooks)
- Records merged into one another: Record Merged, naming both records
- From django-crm 1.13.0, credentials people mint for themselves: API Token Created and API Token Revoked (by its owner, or by an admin revoking someone else's token, in which case the entry names both people), and Calendar Feed Enabled, Calendar Feed Regenerated and Calendar Feed Disabled for a member's task calendar feed. A token entry shows the token's name, its display prefix and its scopes, never the token itself. Turning off a feed that is already off, or revoking a token twice, adds nothing.
Failed sign-ins are recorded but not shown here. From django-crm 1.13.0 every refused sign-in
(a Google sign-in that fails, a wrong, used or expired email link or code, a deactivated account) is
written to the log with the email it claimed and a reason code, never the code or link that was
tried. Nobody failing to sign in has picked an organization yet, so those entries belong to no org
and no org's audit log lists them; filtering by Login Failure shows nothing. They are for whoever
runs the server, in the database and in security_audit.log. Each IP address records at most 20 an
hour.
Each entry shows the event, when it happened, the person it is about and the IP address it came from, newest first. The API also returns the browser's user agent and the request method and path.
Filtering
Filter by event type and by a date range (inclusive, in your org's timezone). Tapping a person on an entry narrows the log to that person, on the web and the phone. An entry about a webhook links to it.
What it deliberately leaves out
The log is filtered to your org, and each entry is cut down to what is safe to show:
- Only details the server wrote, plus the names an event is about. An entry's extra details are limited to ids, counts and sentences the server itself composed. The only typed text shown is a merge's two record names and an API token's name and owner, each on its own event. Anything else a caller could have typed is not returned.
- No other tenant's name. An organization switch does not say which org the person came from.
- No tokens in URLs. Paths under
/api/public/can carry a token, so only that prefix is shown.
API
GET /api/org/audit-log/?event_type=WEBHOOK_PAUSED&from=2026-09-01&to=2026-09-30
Paginated with limit and offset (25 by default, at most 100). actor takes a user id. The
response carries the page under results plus the list of event_types with their labels.
The endpoint answers a signed-in admin session only. A personal access token or the org API key is refused whatever scopes it carries, the same as the webhooks API, so a leaked token cannot read what the org has recorded about it.
See also
- Webhooks: why an endpoint can pause itself.
- Key concepts: roles, and who counts as an admin.