Audit Log
Every Organization keeps an audit log: a chronological record of the significant actions taken in that Organization — who did what, to which object, and when. Use it to answer questions like “who deleted the staging Environment?” or “when was this app last scaled, and by whom?”.
What is recorded
Each entry captures:
- Action — one of
create,update,delete,invite,join,leave,deploy,rollback,promote,scale,restart,transfer,publish,unpublish,credentials_read,block,unblock,verify,release. - Who — the ID of the user who performed the action, or
nullwhen the platform acted on its own (transfer blocks, background domain checks, automatic token revokes). - What — the kind of object (
organization,project,environment,resource,group,secret,variable,invitation,domain,deploy_token,git_connection,repo_link) and its ID. - When — a UTC timestamp.
- Details — action-specific context, such as the Resource name, the Environment it lives in, the new replica count for a scale, or a custom domain that was added or removed. A released domain is recorded twice: once for the organization that released it, once for the organization that was serving it. A blocked or unblocked entry’s details always name the reason (currently always the monthly transfer allocation).
Recorded actions include:
| Object | Actions |
|---|---|
| Organization | created, updated, deleted, ownership transferred |
| Project | created, updated, deleted; member capabilities changed; member removed |
| Environment | created, updated, deleted, deployment triggered, promoted from another environment, deployment rolled back |
| Resource | created, updated, deleted, scaled, restarted, deployment triggered, rolled back, database or bucket attached or detached, blocked or unblocked for exceeding the monthly transfer allocation, custom domain added, verified (by you or the background check), released, removed, or expired unverified |
| Object Storage | bucket made public or private, access credentials read, storage-tier move started or abandoned, object deleted |
| Group | created, updated, deleted, member added or removed, project access granted, changed or revoked, per-environment override set or removed |
| Secret | created, updated, deleted — by scope (Organization, Project, or Environment) |
| Variable | Organization or Environment variable set or removed |
| Invitation | sent, resent, cancelled, accepted |
| Deployment token | created, revoked (by a person, or automatically with a reason) |
| GitHub/GitLab connection | connected, disconnected |
| Repository link | linked or changed, unlinked, Deploy latest run |
Secret entries record the secret’s scope and name only — never its value. Variable entries likewise record the variable’s scope and key, not its value.
The log records changes, not reads — viewing a page or listing Resources leaves no entry. The one deliberate exception is reading an Object Storage bucket’s access credentials, which is always logged because the credentials grant standing access.
Who can view it
Only the Organization’s Owner and Admins can read the audit log. Regular members — and project guests, who are not Organization members at all — receive a permission error. See Access Control for how these roles work.
Reading the log
The audit log is exposed through the platform API at your Organization’s audit-logs endpoint. You can call it with your CLI’s API token — paas auth token prints it for scripting:
curl -H "Authorization: Bearer $(paas auth token)" \
"https://api.d2o.io/api/v1/organizations/acme/audit-logs"
For self-hosted installations, substitute your API origin. Entries come back newest first:
[
{
"id": "8f2c1e0a-6b7d-4a2e-9c31-5d8e0f4a2b91",
"organization_id": "1b9e7d34-2a5f-4c8e-b061-7f3a9c2d5e10",
"user_id": "c4a2f8d1-9e3b-47c6-8a50-2b6d1e9f7c34",
"action": "scale",
"resource_type": "resource",
"resource_id": "5e0d3b7a-1f9c-4826-a4d2-8c7b5a1e9f03",
"details": {
"name": "web",
"replicas": 3,
"environment": "production"
},
"created_at": "2026-08-30T14:12:07.412391Z"
},
{
"id": "0a7b5c3d-8e1f-42a9-b6c4-3d9e2f8a1b05",
"organization_id": "1b9e7d34-2a5f-4c8e-b061-7f3a9c2d5e10",
"user_id": "c4a2f8d1-9e3b-47c6-8a50-2b6d1e9f7c34",
"action": "create",
"resource_type": "resource",
"resource_id": "5e0d3b7a-1f9c-4826-a4d2-8c7b5a1e9f03",
"details": {
"name": "web",
"type": "WebApp",
"environment": "production"
},
"created_at": "2026-08-28T09:44:51.208763Z"
}
]
Paging
Two query parameters control paging:
limit— entries per page. Defaults to 50; capped at 100.offset— how many entries to skip. Defaults to 0.
curl -H "Authorization: Bearer $(paas auth token)" \
"https://api.d2o.io/api/v1/organizations/acme/audit-logs?limit=100&offset=100"
Next steps
- Access Control — the roles that gate audit log access
- Managing Your Organization — members, roles, and ownership
- CLI Overview & Authentication — logging in and API tokens