Skip to main content

Audit

Every state change in Nexa is recorded in an immutable audit log. No soft deletes, no mutations — only appends. Audit is the source of truth for compliance, finance, and incident postmortems.

What gets audited

  • Case lifecycle transitions.
  • Policy creates, updates, activations, deactivations.
  • Demand requests and approvals.
  • Allocation decisions and overrides.
  • Booking attempts, confirmations, cancellations, manual overrides.
  • Notification sends, resends, and bounces.
  • Manual-review claims, actions, and resolutions.
  • Agent runs with their tool calls.
  • Payment tokenizations and revocations.
  • Contract loads, adjustments, and deactivations.
  • Auth events — logins, token refreshes, role grants.

Shape

{
"urn": "urn:nexa:audit:abc",
"entity": "case",
"entityUrn": "urn:nexa:case:xyz",
"action": "reaccommodate",
"actor": {
"urn": "urn:nexa:user:ops-42",
"role": "OPS_SUPERVISOR",
"tokenId": "…"
},
"reason": "airline re-routed due to MAD closure",
"before": { "nextFlight": { "number": "XX125", "scheduledDeparture": "…" } },
"after": { "nextFlight": { "number": "XX130", "scheduledDeparture": "…" } },
"ip": "203.0.113.4",
"at": "2026-04-22T18:42:11Z"
}
  • before/after snapshots capture only the fields that changed — not the entire entity.
  • reason is required on manual actions; system actions use canned strings like system/allocation-retry.
  • ip is only stored for human actors.

Write path

Audit writes are asynchronous by design — audit never blocks the business flow. The sequence:

  1. Business action completes successfully.
  2. An audit.event is published.
  3. The audit subscriber persists the entry to Nexa's append-only audit store.
  4. On subscriber failure, the event is re-enqueued; events spool durably until the audit store accepts them.

In the very rare event audit is lost, a background reconciler catches the gap by diffing aggregate updatedAt timestamps against the last known audit entry.

Read path

# Everything for a case
curl "https://us-central1.api.nexastudio.io/audit?entity=case&entityUrn=$CASE_URN" \
-H "Authorization: Bearer $TOKEN" | jq

# Filter by actor
curl "https://us-central1.api.nexastudio.io/audit?actor=urn:nexa:user:ops-42&since=2026-04-01"

# Filter by action
curl "https://us-central1.api.nexastudio.io/audit?action=override&limit=100"

Returns JSON pages with cursor-based pagination.

Retention

Audit is never deleted. For data-protection compliance, PII is stripped at ingest — audit stores reference IDs and actions, not passport numbers or full passenger names.

Audit is partitioned by month for efficient cold-storage archival. A nightly export drops closed months into a long-term archive.

Tamper-evidence

  • Audit documents are append-only — no service in Nexa has update or delete permission on the collection.
  • Each document has a cryptographic hash of the previous document for the same entity (hash-chain). Anomalies in the chain are detected by a weekly verifier and reported.
  • For tenants on a regulated compliance posture, the hash root is anchored in a third-party timestamping service (RFC 3161).

UI

The Ops Console exposes a case-level audit viewer with:

  • Timeline rendering of actions.
  • Diff-view of each change.
  • Filter-by-actor, filter-by-action controls.
  • CSV export for the period.

Finance uses a savings-report view derived from audit joined against reservations.

What audit is not

  • Not logs. Application telemetry lives separately. Audit is business-state history.
  • Not metrics. Audit answers "what changed and why", not "how long did it take".
  • Not performance-critical. It's async and bounded; an audit backlog never harms booking throughput.
Was this helpful?