Audit log API reference
Read, seal, export and verify the hash-chained action log: entry fields, the kind vocabulary and the export bundle your own verifier checks.
Last updated:
Every consequential action the platform takes lands in a hash-chained, signed log that your compliance team — or your customer's — can verify independently. Reading and sealing it requires nothing special: the same bearer API key as everywhere else on the v1 surface.
Chain and seal
/v1/audit/log
Pages through the log from a sequence number given as `from`, 5000 entries at a time, with `nextFrom` pointing at the next page.
Entry fields
| Name | Type | Description |
|---|---|---|
kind
|
string | What happened, from the vocabulary below. |
at
|
timestamp | When the platform recorded it. |
summary
|
string | A one-line human-readable account. |
seq
|
integer | The entry's position in the chain. |
prev
|
string | The hash of the previous entry. |
hash
|
string | This entry's own hash, computed over its canonical encoding. |
The kind vocabulary
Kinds include session.created and session.released, the verbs verb.observe, verb.act and verb.extract, credential.released and credential.denied, the safety refusals gate.refused and destination.refused, task.started and task.finished, workflow.block, takeover.granted and takeover.released, trigger.fired, and the key events key.rotated and secret.rotated.
/v1/audit/seals
Lists the seals and the entry ranges each one covers.
/v1/audit/seal
Signs a named range with Ed25519 and returns `{sealId, seal, covers}` — or 400 when nothing new is there to seal.
/v1/audit/export
Exports a `browserberg-action-log-v1` bundle of entries and seals, paged at 50000 entries.
Verify without us
The bundle carries howToVerify, and running a verifier needs nothing from us: replay the chain, then check every seal. Neither mechanism suffices alone — one misses a shortened tail, the other an edited entry — so treat them as one check with two halves, never as alternatives.
Seals name their algorithm. ed25519 is the original; ecdsa-p256-sha256 (since 1.4) is what the hosted service seals with, because its signing key lives in a KMS that offers P-256 and not Ed25519. An ECDSA signature is the 64-byte IEEE P1363 r||s form, base64, verified with SHA-256 over the same canonical seal string. A verifier refuses an algorithm it does not know rather than guessing.
/v1/audit/verify
Runs the platform's own verification — it exists for support; run your own verifier, that is the point.
What the log is not
Honesty about scope: the export is not a timestamping authority, and it is not proof the browser behaved as described. It is a tamper-evident record of what the platform said it did — strong enough that an altered, removed or truncated account shows, and no stronger.
Leave a trace, read it back
Creates and releases a session, then reads the first chain entries with their hashes.
Requires: api-key
BASE="https://browserberg.com"
AUTH="Authorization: Bearer $BROWSERBERG_API_KEY"
JSON="Content-Type: application/json"
# Leave a trace to read back.
ID=$(curl -s -X POST "$BASE/v1/sessions" -H "$AUTH" -H "$JSON" -d '{"ttlSeconds": 60}' \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["session"]["id"])')
curl -s -X DELETE "$BASE/v1/sessions/$ID" -H "$AUTH" > /dev/null
# Every entry carries seq, prev and hash: a hash chain a verifier replays.
curl -s "$BASE/v1/audit/log?from=0" -H "$AUTH" \
| python3 -c 'import json,sys; r = json.load(sys.stdin); print(json.dumps([
{ "seq": e["seq"], "kind": e["kind"], "summary": e["summary"] }
for e in r["entries"][:4]], indent=2))'
[
{
"seq": 0,
"kind": "session.created",
"summary": "session Fi3VkukDoaZf3fQgFzHI6w ready (warm start)"
},
{
"seq": 1,
"kind": "verb.act",
"summary": "1 pre-resolved step(s)"
},
{
"seq": 2,
"kind": "session.released",
"summary": "session Fi3VkukDoaZf3fQgFzHI6w ended: client_released"
},
{
"seq": 3,
"kind": "session.created",
"summary": "session I3Vb_fM3rAKTp_e8k2n5jg ready (warm start)"
}
]