Skip to content

Audit events and SIEM export

Torii records authentication and administration events automatically. Your backend can add application-owned events to the same environment-scoped, tamper-evident log, then export both kinds through the Server API.

All calls use your environment’s secret key. Never expose that key to a browser or native app.

Torii records successful sign-up, sign-in, sign-out, authentication refusals, OAuth failures, authorization denials, role and permission changes, invitation lifecycle changes, and other administrative operations. See the built-in audit event actions for the complete server-owned catalog and the trigger for each identifier.

An unknown-account sign-in refusal records user.sign_in_failed without a user ID. Password and email-code refusals target the environment; OAuth provider refusals retain a user target with a null ID. The authentication response stays the same for known and unknown accounts, so the audit trail does not introduce an account-existence leak.

Send POST /api/server/v1/audit-events with a unique idempotency key:

Terminal window
curl -X POST https://api.toriiauth.eu/api/server/v1/audit-events \
-H "Authorization: Bearer $TORII_SECRET_KEY" \
-H "Idempotency-Key: order-4821-approved-v1" \
-H "Content-Type: application/json" \
-d '{
"action": "customer.caterflow.order.approved",
"result": "success",
"schemaVersion": 1,
"occurredAt": "2026-08-11T12:00:00Z",
"actor": { "type": "server" },
"targets": [
{ "type": "customer.caterflow.order", "id": "order_4821" }
],
"context": {
"ipAddress": "192.0.2.44",
"userAgent": "caterflow-web/2.1"
},
"correlationId": "0198a123-4567-7000-8000-000000000001",
"metadata": { "approvalRole": "manager" }
}'

Actions and custom target types use your customer. namespace. Keep each ID stable after release so SIEM rules do not depend on display text. An actor may be the calling server or a Torii user from the same environment. A user target is also checked against that environment.

Use one idempotency key for every logical event and reuse it for retries. The same key and semantically identical JSON, including JSON with reordered object keys, returns the original stored event. Reusing the key with changed content returns 409 idempotency_key_reused.

The response deliberately keeps two sources separate:

Field Source Use
context.ipAddress, context.userAgent Claimed by your request The end-user or application context in which the action happened
producer.secretKeyId Resolved by Torii The credential that submitted the event
producer.ipAddress, producer.userAgent Observed by Torii on the API request Evidence about the submitting backend connection

Do not treat claimed context as proof of the submitting system. Torii stores it as supplied after format and size validation. producer is independent and cannot be set in the request. It is null on Torii’s built-in events because those events were not submitted with a customer secret key.

POST /api/server/v1/audit-events/search returns events in ascending environment sequence order. Omit the checkpoint to start at the first retained event that has a sequence. Events written before sequenced audit chains were introduced require a bounded backfill. This is not a tail-from-now subscription:

Terminal window
curl -X POST 'https://api.toriiauth.eu/api/server/v1/audit-events/search?limit=100' \
-H "Authorization: Bearer $TORII_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"page": { "mode": "poll" },
"filters": {
"results": ["failure", "denied"]
}
}'

The response contains items and:

{
"mode": "poll",
"checkpoint": "eyJzZXF1ZW5jZSI6MTIzNH0",
"hasMore": false
}

Treat checkpoint as opaque. Send it back as {"page":{"mode":"poll","checkpoint":"..."}} with the same filters. When hasMore is true, immediately continue from the returned checkpoint to drain the backlog. Each poll reads through a fixed high-water sequence. Events committed while that request is running remain after its checkpoint and are eligible for the next request. When no event matches, the checkpoint still advances past the non-matching history that the poll examined.

Commit a checkpoint only after the SIEM has durably accepted every items entry in that response. If delivery fails, keep the previous checkpoint and retry. The same events can then be returned again, so deduplicate on the stable event id.

Persist one checkpoint per environment and filter configuration. Changing filters while retaining a later checkpoint can skip older events that newly match. Store the new checkpoint and the SIEM batch acknowledgement atomically where possible.

Each environment has an audit PII deletion policy under Audit log in the dashboard. The default is Scrub immediately. When a user is deleted, Torii clears metadata, IP addresses, and user agents from earlier events involving that user and from the user.deleted event itself. Stable evidence remains, including the event ID, sequence, action, result, timestamps, actor and target IDs, correlation ID, and tamper-evidence chain.

Choose Retain with the audit log when your accountability requirements need the complete event context. In that mode, the same personal-data fields remain until the event reaches the environment’s normal audit retention boundary. Audit rows are never physically deleted or renumbered as part of user deletion.

Policy changes apply to future user deletions only. Saving a different policy does not sweep existing events. A forward SIEM poll returns the stored form of events after its checkpoint. Torii cannot remove personal data from events that your SIEM already ingested, so apply the corresponding retention and deletion controls there as well.

Dashboard clients can read or update the setting through GET|PATCH /api/platform/projects/{projectId}/environments/{environmentId}/audit-settings. The patch body is one of:

{ "deletionPolicy": "SCRUB_ON_DELETION" }
{ "deletionPolicy": "RETAIN_UNTIL_AUDIT_RETENTION" }

Use bounded mode for investigations and backfills:

Terminal window
curl -X POST 'https://api.toriiauth.eu/api/server/v1/audit-events/search?limit=100' \
-H "Authorization: Bearer $TORII_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"page": {
"mode": "bounded",
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-08T00:00:00Z",
"order": "asc"
},
"filters": {
"actions": ["user.signed_in", "user.sign_in_failed"],
"actorTypes": ["user"],
"targetTypes": ["user"]
}
}'

The range is [from, to) over recordedAt, the time Torii stored the event, not the customer-supplied occurredAt. A bounded request may span at most 31 days. When page.hasMore is true, send its opaque cursor in the same bounded request. The final page has cursor: null.

Available filters are actions, actorTypes, actorIds, targetTypes, targetIds, results, and correlationId. List values match any value within that field; different filter fields are combined with AND.

Keep the complete Torii event as the source record. These fields are useful for normalization:

Torii field SIEM role
id Deduplication key
environmentId Tenant or data partition
sequence Environment ordering and polling position
action Stable event action
result Outcome: success, failure, or denied
occurredAt Time the source says the action happened
recordedAt Time Torii ingested the event
actor Acting user, platform user, server credential, or system
impersonatorId Operator behind an impersonated user session
targets Affected resources
context Customer-claimed client context
producer Torii-observed submitting backend
correlationId Request, trace, or workflow correlation
metadata Action-specific structured details
  • Request body: 24 KiB. metadata: 16 KiB. Up to 20 targets.
  • limit: 1 through 100. Bounded ranges: at most 31 days.
  • Each list filter accepts at most 100 distinct values. Actions and target types accept at most 191 characters, actor types 32, and target IDs 512.
  • occurredAt: no more than five minutes in the future. In sandbox it must also fit within the sandbox audit retention window.
  • Idempotency-Key: 1 through 255 characters. Context user agents are limited to 512 characters, and context IP addresses must be IPv4 or IPv6 literals.
  • 400 invalid_audit_event: schema, timestamp, size, namespace, or value error.
  • 400 invalid_audit_search: invalid filters, range, cursor, checkpoint, or limit.
  • 401: missing or invalid secret key.
  • 402 audit_storage_not_enabled: audit storage is not enabled for the production environment.
  • 402 audit_storage_capacity_reached: the environment cannot store another event.
  • 404 resource_not_found: a referenced Torii resource is absent or belongs to another environment.
  • 409 idempotency_key_reused: an idempotency key was reused for different content.
  • 429 rate_limit_exceeded: append attempts reached the 600-per-minute threshold for either the environment or the secret key. Successful, replayed, and rejected append attempts all count. Wait for the seconds in the Retry-After response header before retrying. Search is not subject to this ingestion limit.

Search and append are always scoped from the secret key. Request bodies cannot select another environment.