Compliance Audit-Log API
A compliance-grade, append-only, tamper-evident audit read surface. Every audit record is linked into a per-org SHA-256 hash chain, so any edit, gap, or deletion is detectable. This endpoint returns recent rows and reports whether the returned set verifies as a contiguous chain.
Endpoint
GET /api/admin/apps/:app_id/audit-log
Returns recent audit rows for an app, with chain verification.Auth: app admin (app owner or superuser).
Query Parameters:
org_uuid(optional): filter to a single chain. The chain key
is the org_uuid; omit for the platform (nil) chain mixed with all orgs.
Mixing chains disables action(optional): filter by action string.limit(optional): default 100, capped at 500.data— rows ordered ascending by(chain_key, seq).chain_valid—true/falsewhen the returned rows form one chain
chain_valid.
Output (200):
~~~json
{
"data": [
{
"occurred_at": "2026-06-14T12:00:00.000000000Z",
"actor_type": "user",
"actor_email": "admin@example.com",
"org_uuid": "…",
"app_id": 50,
"action": "app.security.policy_updated",
"target_type": "org_security_policy",
"outcome": "success",
"chain_key": "…",
"seq": 42,
"prev_hash": "
seq range; null when contiguity can't be
established (an action filter skipped rows, or rows span multiple chains).Tamper-evidence
Each row carries prev_hash (the prior row's record_hash) and
record_hash = SHA-256(canonical(record) || prev_hash). Chains are partitioned
by chain_key (the org_uuid, or the nil UUID for the shared platform chain);
(chain_key, seq) is unique and dense. Verification recomputes the chain and
flags any edited field, gap (deleted middle row), or broken link. Writes are
append-only and serialized per chain — there is no update or delete path.