api reference
Intended Documentation
API Reference: Audit
Query the per-tenant SHA-256 audit chain, verify its integrity, and export HMAC-signed evidence bundles. Exact endpoints, response shapes, and the precise verification guarantee.
Audit API#
Every state-changing runtime operation appends to a per-tenant, SHA-256 hash-chained audit log as a side effect — you do not opt in. Each entry stores the hash of the previous entry, so any later tampering breaks the chain and is detectable. This API lets you query that chain, verify its integrity, and export a signed evidence bundle for a single intent.
Each tenant has its own hash chain and its own signing key. Audit entries never cross the tenant boundary, and evidence is signed with the tenant's own secret.
What the chain stores#
The audit-grade substrate is the AuditEntry record: { id, tenantId, correlationId, intentId, actorId, actorType, eventType, payload, previousHash, entryHash, createdAt }, unique on (tenantId, entryHash). The entryHash is a SHA-256 over the canonical, key-sorted JSON of the entry, and previousHash links to the prior entry's hash (the chain head's previousHash is null). Appends run inside a serializable transaction. There are 40+ eventTypes — INTENT_RECEIVED, AUTHORITY_DECISION, TOKEN_ISSUED, EXECUTION_ATTEMPTED, EXECUTION_RESULT, ESCALATION_EVENT, and so on.
Info
A single POST /intent typically writes several entries (received → decision → token/execution → result). The audit.entriesWritten and audit.latestHash in the /intent response tell you how many were appended and the resulting chain head.
Query Tenant Audit Events#
Response: { tenantId, total, limit, offset, events: [...] }. Each event carries its eventType, payload, correlationId, entryHash, previousHash, and createdAt.
Verify Chain Integrity#
Response:
If the chain is broken, valid is false and brokenAt is the index of the first failing entry:
Info
A cross-tenant sweep, POST /audit/verify-chain, runs the same verification across every tenant and raises an ESCALATION_EVENT alert on any broken chain. Note a known reporting quirk: its per-tenant checkedRecords field is always 0 (the underlying verifier returns totalEntries, not checkedRecords). The valid / brokenAt results are correct; only that count is wrong. The single-tenant endpoint above is unaffected.
Generate an Evidence Bundle#
Response (EvidenceBundle):
| Field | Notes |
|---|---|
integrityHash | sha256:<hex> over the serialized events. |
signature | hmac-sha256:<hex> over intentId:integrityHash, keyed with the tenant's own stored secret. |
chainValid | Whether the underlying chain verified at generation time. |
Warning
On what "signed" means here. The evidence signature is a symmetric HMAC-SHA256 keyed with the tenant's own secret. Verifying it (verifyEvidenceBundle, with timing-safe comparison) requires possession of that same secret. It is therefore not publicly or asymmetrically verifiable the way the Ed25519 decision token is — a third party cannot independently verify the bundle without the tenant key. State this precisely in any compliance claim.
| Status | Code | Cause |
|---|---|---|
400 | VALIDATION_ERROR | Bad path params. |
404 | NO_AUTHORITY_KEY | Tenant has no ACTIVE signing key. |
404 | NO_AUDIT_EVENTS | No audit events for that intent. |
500 | EVIDENCE_BUNDLE_FAILED | Generation failed closed. |
Run-Stream Endpoints#
The runtime also keeps an unsigned, unchained narrative stream (AuditRun / AuditRunEvent) for replay and export, distinct from the tamper-evident chain above.
| Method | Path | Purpose |
|---|---|---|
| GET | /audit/run/:runId?tenantId=… | Fetch the run's event stream. |
| GET | /audit/run/:runId/replay?tenantId=… | Replay the run deterministically. |
| GET | /audit/run/:runId/export?tenantId=… | Export the run's narrative. |
| GET | /audit/:tenantId/timeline?limit=… | Executive-readable timeline (limit 1–200, default 100). |
Info
The narrative stream is for human review and replay; it is not the tamper-evident substrate. Tamper-evidence comes from the hash-chained AuditEntry log queried above. Keep the two distinct in any audit narrative.
Enterprise Export Jobs#
For formal, asynchronous compliance exports, use the admin export jobs. These require the enterprise audit:read permission and resolve through the tenant boundary.
| Method | Path | Purpose |
|---|---|---|
| POST | /admin/audit-exports | Create an export (201). |
| GET | /admin/audit-exports?tenantId=… | List exports. |
| GET | /admin/audit-exports/:id?tenantId=… | Export status. |
| GET | /admin/audit-exports/:id/download?tenantId=… | Download the artifact (404 AUDIT_EXPORT_ARTIFACT_NOT_READY until ready). |
The download response carries the artifact plus x-intended-artifact-digest and x-intended-artifact-signature headers.
Warning
The system provides the mechanisms of audit — an immutable hash chain, signed export, and tamper detection — but it encodes no compliance-framework control IDs (no SOC 2, ISO 27001, or EU AI Act mappings live in code). Do not represent these endpoints as a certified control mapping; represent them as the evidence substrate an auditor can build on.
Next steps#
- Audit Export — the operator workflow for evidence exports
- Intents API — the calls that write to this chain
- Tenant Trust Boundary — why each tenant's chain and keys are isolated