Four endpoints against your operator's append-only hash-chained log. All require bearer authentication. Operators and human members can read their account's log; an agent-bearing credential can only list entries attributed to that verified agent. For the conceptual model, see/docs/concepts/audit.
Tail of recent audit entries for the authenticated operator, ordered newest-first. Use this for live monitoring and incremental polling. For full date-range exports, use /v1/audit/export instead.
# First request — get the watermark
curl -s "https://api.getstack.run/v1/audit?limit=20&agent_id=agt_support" \
-H "Authorization: Bearer $STACK_API_KEY"
# Subsequent requests — only entries newer than `max_timestamp`
curl -s "https://api.getstack.run/v1/audit?since=$WATERMARK&agent_id=agt_support" \
-H "Authorization: Bearer $STACK_API_KEY"{
"entries": [
{
"entry_id": "aud_z9…",
"timestamp": 1747913532614,
"trace_id": "req_abc",
"operator_id": "op_acme",
"agent_id": "agt_support",
"passport_jti": "pp_8f3a",
"layer": "vault",
"action": "passport.revoke_cascade",
"outcome": "success",
"duration_ms": 0,
"error_code": null,
"error_message": null,
"prev_entry_hash": "ab3f…7c2e",
"entry_hash": "c104…d8a1"
}
],
"max_timestamp": 1747913532614
}Cascade revokes write one passport.revoke entry for the parent + one passport.revoke_cascade entry per child revoked. Filter by passport_jti to see the chain for a single passport.
Paginated export of audit rows for the authenticated operator. Supports JSON (default), NDJSON (line-delimited JSON - stream-friendly), and CSV (spreadsheet-friendly). Each response is capped at 50,000 rows. Agent-bearing credentials cannot export the account log.
curl -s "https://api.getstack.run/v1/audit/export?from=$(date -u -d '1 day ago' +%Y-%m-%dT%H:%M:%SZ)&format=ndjson" \
-H "Authorization: Bearer $STACK_API_KEY" \
> audit.ndjson{
"operator_id": "op_acme",
"count": 2,
"from": "2026-04-22T00:00:00Z",
"to": null,
"rows": [
{
"entry_id": "aud_A…",
"timestamp": 1747913500000,
"trace_id": "req_abc",
"operator_id": "op_acme",
"agent_id": "agt_support",
"passport_jti": "pp_8f3a",
"layer": "vault",
"action": "passport.issue",
"outcome": "success",
"duration_ms": 42,
"prev_entry_hash": "0000…0000",
"entry_hash": "ab3f…7c2e"
},
{
"entry_id": "aud_B…",
"timestamp": 1747913532614,
"layer": "vault",
"action": "passport.revoke",
"outcome": "success",
"prev_entry_hash": "ab3f…7c2e",
"entry_hash": "ab3f…81d3"
}
]
}Returns the most recent entry_hash for your operator along with the total number of rows. Anchor this value externally to prove later that your log was not retroactively rewritten.
{
"operator_id": "op_acme",
"latest_entry_hash": "ab3f…81d3",
"latest_timestamp": 1747913532614,
"total_entries": 184723,
"observed_at": "2026-04-23T14:32:12.603Z"
}For brand-new operators with zero rows, latest_entry_hashand latest_timestamp are nulland total_entries is 0.
Re-walks the chain for your operator and reports whether it is intact. Content tampering (mutated row fields) and chain tampering (reordered or missing prev_entry_hash links) both surface as a first_break pointer.
{
"operator_id": "op_acme",
"verified_at": "2026-04-23T14:35:00.000Z",
"valid": true,
"total_checked": 184723,
"head_entry_hash": "ab3f…81d3"
}{
"operator_id": "op_acme",
"verified_at": "2026-04-23T14:35:00.000Z",
"valid": false,
"total_checked": 912,
"head_entry_hash": "ab3f…81d3",
"first_break": {
"entry_id": "aud_X…",
"timestamp": 1747912000000,
"reason": "hash_mismatch",
"expected": "d48a…1f02",
"actual": "ee91…22c5"
}
}Two failure reasons are reported: