Audit log
The append-only record of who did what across your organization. Read it on the Audit page in the Portal or query it with the SDK using cursor pagination.
What it is. A structured, append-only record of activity across your organization: who did what, to which resource, with what outcome.
Use it when you need to answer "who deployed this", "who approved that review", "which runs were denied", or you are building compliance reporting on top of Swirls.
Works with the Audit page in the Portal, the SDK audit client, and access policies (grants and denials land here).
What it records
Every part of the platform emits audit events: project and deployment lifecycle, repository linking, human-in-the-loop reviews, trigger and form activity, chat sessions, workflow execution outcomes, identity verification and credential issuance, identity provider registration, member attribute changes, connection bindings and token issuance, and key management operations.
The audit log answers who, what, and outcome. It is not the debugging surface for runs; step-by-step run detail lives in Traces.
Event shape
Each event carries:
| Field | Meaning |
|---|---|
subject | Dotted event name: swirls.audit.<resource_type>.<action>, for example swirls.audit.deployment.activated. |
occurredAt / ingestedAt | When the event happened and when it was recorded. |
actorId, actorType | Who acted. actorType is user, service, or agent. |
orgId, projectId | Tenant scope. Personal events carry no orgId. |
resourceType, resourceId, action | What was acted on and how. |
outcome | success, failure, or denied. |
workflowId, executionId, traceId | Correlation to runs and traces. |
errorCode, metadata | Failure class and structured context. |
Scoping
Reads are scoped by your authenticated identity. There are two views:
- Organization: every event in your active organization. Available to every member of the organization.
- Personal: your own events that belong to no organization, such as account-level actions.
The scope always comes from your session. IDs supplied in a request are ignored server-side, so one organization can never read another's log.
Reading it in the Portal
The Audit page shows an overview with an activity chart and a filterable event list. Filter by outcome and resource type, and switch between the organization and personal tabs. Events load newest first, 50 at a time.
Reading it with the SDK
The audit client exposes two methods:
// Organization events
const org = await swirls.client.audit.listByOrg({
orgId: "org", // ignored; the server uses your active org
limit: 100,
})
// Your personal events
const personal = await swirls.client.audit.listByActor({
actorId: "me", // ignored; the server uses your identity
limit: 100,
})Both return { data, nextCursor? } with events newest first.
Cursor pagination
Pass limit (1 to 500, default 100) and the nextCursor from the previous page:
let cursor: string | undefined
do {
const page = await swirls.client.audit.listByOrg({
orgId: "org",
limit: 200,
cursor,
})
for (const event of page.data) {
process(event)
}
cursor = page.nextCursor
} while (cursor)The cursor is opaque; store and pass it back as-is. A missing nextCursor means you reached the last page. The cursor is stable across events with identical timestamps, so pages never drop or duplicate rows at boundaries.
Common mistakes
- Using the audit log to debug a run. It records that a workflow ran and how it ended, not what each step did. Use Traces for step detail.
- Passing another org's
orgId. The server scopes to your session; the parameter is ignored. - Parsing the cursor. It is an opaque token, not a timestamp or offset.
- Filtering client-side across many pages when the subject prefix would do. Events follow the
swirls.audit.<resource_type>.<action>convention, so match onresourceTypeandactionfields instead of string-splitting subjects.
Further reading
- SDK audit reference: full method signatures
- Access: the policies whose grants and denials land here
- Observability: traces, the run debugging surface