Audit API

Every action that mutates state writes an AuditEntry row. The chain is per-Tenant and HMAC-signed by AUDIT_HMAC_SECRET. The two endpoints below let an operator read the chain and verify its integrity. See Concepts — Security for the model.

List audit entries

GET /api/audit?limit=100&cursor=...

Returns the most recent entries for the caller's Tenant. Pagination is cursor-based; pass the returned nextCursor on the next call.

200 OK
{
  "items": [
    {
      "id": "ae_01",
      "tenantId": "ten_01",
      "occurredAt": "2026-05-25T11:30:00.000Z",
      "actorUserId": "usr_01",
      "kind": "agent.chat",
      "entity": "agent:sales",
      "summary": "User asked the sales agent about pricing",
      "prevHash": "...",
      "hash": "..."
    }
  ],
  "nextCursor": "ae_00"
}

Requires Owner or Admin.

Verify the audit chain

GET /api/audit/verify

Recomputes the HMAC chain end-to-end against the caller's Tenant and returns the result. A successful verification means every row's stored hash equals the recomputed value of HMAC-SHA-256(content || prevHash). A failure pinpoints the first row at which the chain breaks — useful for forensic work after a suspected tamper.

200 OK
{
  "tenantId": "ten_01",
  "ok": true,
  "rowsChecked": 12834,
  "elapsedMs": 217
}

200 OK (failed verify)
{
  "tenantId": "ten_01",
  "ok": false,
  "rowsChecked": 12834,
  "firstBreakAt": "ae_4421",
  "detail": "Stored hash does not match recomputed HMAC"
}

500 Internal Server Error
{ "error": "audit_hmac_secret_missing" }

Requires Owner.

What gets audited

The following kinds are written into the chain:

  • agent.chat, agent.tool_use, agent.tool_result
  • agent.created, agent.patched, agent.paused, agent.resumed, agent.archived
  • tenant.created, tenant.patched, tenant.archived
  • brand.created, brand.patched, brand.suspended, brand.offboarded
  • role.granted, role.revoked
  • secret.created, secret.updated, secret.deleted
  • approval.opened, approval.resolved
  • trigger.fired, broadcast.fired
  • signin.success, signin.rejected

Operational notes

  • AUDIT_HMAC_SECRET is mandatory on NODE_ENV=production — the platform refuses to boot without it.
  • Verification cost is linear in the number of rows but parallel-safe per Tenant — verifying one Tenant doesn't block writes to another.
  • The verify endpoint never modifies the chain; it's safe to call from a cron / external monitor.

Source: src/platform/audit.ts, src/platform/api.ts.