DocsAPI referenceBrowse
API reference
Every route the control plane answers, generated from the OpenAPI document it serves about itself. Two kinds of key, one scoping rule, one error shape — and every bounded reading says what it read.
curl -s http://localhost:4319/v1/openapi.json | jq .info.title
Authentication
Tenant keys reach one log; admin keys reach every log. Webhook and signed-link secrets work only on the route that issued or configured them.
4 authentication schemesShow details
Keys and scoping. Two kinds of bearer: an admin key (configured on the plane) sees every log and every route; a tenant key (ak_…, minted by an admin) is scoped to exactly one log. Every route that names a log applies one rule — scopedLog() — and a tenant asking about any log but its own gets a flat 403 {"error":"forbidden"} that does not confirm whether that log exists. A third credential, the write-only webhook secret, is accepted only on /v1/ingest/*.
| Scheme | How | Reaches |
|---|---|---|
bearer | Authorization: Bearer <admin key or ak_… tenant key> | An admin key (configured on the plane in AUDITANT_API_KEYS) reaches every log and every route. A tenant key (ak_ + 48 hex, minted by POST /v1/tenants/key) reaches exactly one log. A plane with no admin keys configured is an open local demo and treats every caller as admin. |
webhookSecret | header x-auditant-webhook-secret | Write-only. Accepted on /v1/ingest/* and nowhere else; can write events and do nothing else, so leaking it costs spam, never disclosure. |
vapiSecret | header x-vapi-secret | The same webhook secret under the header name Vapi sends it as. |
clickToken | query t | An HMAC-signed, expiring token from a Slack notification. Only /v1/approvals/click. |
Errors and limits
Failures use one error shape. Bounded reads say which window they examined, and rate-limited routes return the headers needed to retry safely.
Error model7 responses
Errors are always {"error": string} with a status that means one thing: 400 the request is malformed (including a body over 8 MiB, or an event the schema rejects — the message names the field); 401 no usable credential; 403 the credential does not reach that (never a description of what it would have reached); 404 the route or the thing does not exist for an admin; 429 over a per-key ceiling, with Retry-After; 501 the plane is not configured for that (refusing rather than degrading — a decision without a budget store would look like enforcement and isn't); 500 "internal error", never a stack trace.
| Status | Meaning | Body |
|---|---|---|
| 400 | The request is malformed: a required field is missing, a value is out of bounds, the body is not JSON or exceeds 8 MiB, or an event failed schema validation — the message names the field. | { "error": "ts must be RFC 3339 with an explicit offset (field: ts)" } |
| 401 | No usable credential. | { "error": "unauthorized" } |
| 403 | The credential does not reach that. Deliberately flat: a tenant key asking about another tenant's log gets this whether or not that log exists, so nothing can be learned by asking. | { "error": "forbidden" } |
| 404 | No such route, or no such thing — for an admin. A tenant never reaches a 404 for something outside its scope; it reaches the 403 first. | { "error": "no route for GET /v1/nope" } |
| 429 | Over the per-key ceiling for this class of route. Per process; wait Retry-After seconds.headers: Retry-After, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset | { "error": "rate limited", "scope": "decide", "limit": 12000, "windowSeconds": 60, "retryAfterSeconds": 41, "resetAt": "2026-08-20T10:01:00.000Z" } |
| 500 | Something failed on our side. Never a stack trace; the real error reaches the operator's error tracker. | { "error": "internal error" } |
| 501 | This plane is not configured for that (no budget store, no rule store, no self-serve tenants). Refused rather than degraded. | { "error": "policy decisions are not configured" } |
Bounded readingsWindow metadata
Bounded readings. Coverage, approvals and the ledger read a capped window of the log and say so in a window object. A truncated window is a floor, not a total; narrow from/to for an exact figure.
Rate limitsRetry headers
Rate limits apply per key, per process, to ingest, decide and export. x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset are set on every limited response; a refusal is 429 with Retry-After.
Endpoints
Choose a group, then open only the operation you need. Request fields, response fields and examples stay collapsed until then.
Plane3 endpoints · browse
Liveness and self-description. No credential.
GET/healthLiveness, and which logs existno key · details
healthThe container health check. Lists log ids so a probe can also confirm the store is readable.
| Field | Type | Meaning |
|---|---|---|
okrequired | true | |
logsrequired | string[] | Every log id with at least one event. |
{
"ok": true,
"logs": [
"tenant_acme/prod"
]
}GET/v1/openapi.jsonThis documentno key · details
openapiThe plane describes itself, to anyone. There is nothing here a key protects.
POST/v1/ratelimitDurable rate-limit check for a downstream that costs moneyadmin key · details
ratelimitConsumes one unit from a per-caller bucket and a shared global bucket, both persisted in the store so a restart does not hand a caller a fresh allowance. Used by the marketing site's chat. Admin only. The bounds you pass are clamped — a caller that could name its own ceiling could name a useless one.
| Field | Type | Meaning |
|---|---|---|
keyrequired | string | The caller — an IP, a session id. |
caller | LimitSpec | |
caller.max | integer | |
caller.windowSeconds | integer | |
global | LimitSpec | |
global.max | integer | |
global.windowSeconds | integer |
{
"key": "203.0.113.7",
"caller": {
"max": 15,
"windowSeconds": 3600
},
"global": {
"max": 2000,
"windowSeconds": 86400
}
}| Field | Type | Meaning |
|---|---|---|
allowedrequired | boolean | |
remainingrequired | integer | |
resetAtrequired | string | |
scope | "caller" | "global" | Which bucket refused, when one did. |
{
"allowed": false,
"remaining": 0,
"resetAt": "2026-08-20T11:00:00.000Z",
"scope": "caller"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Evidence2 endpoints · browse
Writing to the chain. Asynchronous by design: an append never blocks the agent that emitted it.
POST/v1/eventsAppend events to the chaintenant or admin key · details
appendEventsSeals each event onto its log — assigning seq, prevHash and eventHash under the per-log write lock — and returns the new head. The whole batch is one transaction: all of it lands or none of it does. Every event names its own logId, and a tenant key may only write its own; the scope check runs before anything chains, because an append is permanent. An event the schema rejects is a 400 naming the field, and nothing in the batch is written.
At least one event.
| Field | Type | Meaning |
|---|---|---|
eventsrequired | AuditEventInput[] | |
events[].schemaVersionrequired | "1.0.0" | |
events[].eventIdrequired | string | The emitter's id. Deduplication is the emitter's job; the log records what it is sent. |
events[].tsrequired | string | RFC 3339 with an explicit offset. |
events[].logIdrequired | string | |
events[].actorrequired | Actor | |
events[].actor.kindrequired | "agent" | "human" | "system" | |
events[].actor.idrequired | string | |
events[].actor.version | string | |
events[].actor.mode | "interactive" | "autonomous" | `interactive` — a human was present and approved. `autonomous` — no human in the loop. |
events[].actor.principal | string | Gateway key hash, IAM principal, or OIDC subject — whatever authenticated. |
events[].onBehalfOf | object | |
events[].onBehalfOf.humanId | string | |
events[].onBehalfOf.endUser | string | |
events[].approvedBy | object | |
events[].approvedBy.humanIdrequired | string | |
events[].approvedBy.atrequired | string | |
events[].sessionId | string | A run. The ledger's unit. |
events[].traceId | string | Joins the capture planes. Without it we hold four disconnected logs rather than one account. |
events[].parentEventId | string | |
events[].actionTyperequired | "model_call" | "tool_call" | "tool_response" | "decision" | "delegation" | "escalation" | "human_override" | "policy_decision" | "disclosure" | "lifecycle" | "error" | |
events[].actionrequired | string | |
events[].surfacerequired | Surface | |
events[].surface.planerequired | "model" | "action" | "edge" | "effect" | Which capture plane observed this. Determines what the event can prove. |
events[].surface.adapterrequired | string | `sdk`, `gateway`, `langgraph`, `vapi`, `github`… |
events[].surface.modality | "text" | "voice" | "code" | "infra" | |
events[].inputHash | string | Payloads live in object storage; only hashes chain. |
events[].outputHash | string | |
events[].outcomerequired | "ok" | "error" | "blocked" | "pending_approval" | "reverted" | `blocked` and `pending_approval` require a `policy` record naming what stopped it. |
events[].reason | string | Why, in the actor's own words. Required by `adverse-decision-requires-reason`. |
events[].policy | PolicyRecord | |
events[].policy.decisionrequired | "allow" | "deny" | "pending_approval" | |
events[].policy.policyIdrequired | string | |
events[].policy.policyVersionrequired | string | |
events[].policy.enginerequired | string | |
events[].policy.approvalId | string | |
events[].policy.approver | string | null | |
events[].policy.reasons | string[] | |
events[].policy.monitorMode | boolean | True when the rule ran in monitor mode — recorded, deliberately not enforced. |
events[].cost | Cost | |
events[].cost.currencyrequired | string | |
events[].cost.totalrequired | number | |
events[].cost.breakdown | object | |
events[].cost.breakdown.input | number | |
events[].cost.breakdown.output | number | |
events[].cost.breakdown.reasoning | number | |
events[].cost.breakdown.cacheRead | number | |
events[].cost.breakdown.cacheCreation | number | |
events[].cost.breakdown.toolUsage | number | |
events[].cost.units | object | |
events[].cost.units.inputTokens | integer | |
events[].cost.units.outputTokens | integer | |
events[].cost.units.cacheReadTokens | integer | |
events[].cost.units.cacheCreationTokens | integer | |
events[].cost.units.reasoningTokens | integer | |
events[].cost.units.seconds | number | |
events[].cost.units.characters | integer | |
events[].cost.model | string | |
events[].cost.provider | string | |
events[].cost.attributionCompleterequired | boolean | False ⇒ the upstream priced nothing. Never render this as $0. |
events[].art12 | object | EU AI Act Art 12(3) names these three specifically. |
events[].art12.periodStart | string | |
events[].art12.periodEnd | string | |
events[].art12.inputRefs | string[] | |
events[].art12.humansInvolved | string[] |
{
"events": [
{
"schemaVersion": "1.0.0",
"eventId": "evt_8f2c1a",
"ts": "2026-08-20T10:00:00.000Z",
"logId": "tenant_acme/prod",
"actor": {
"kind": "agent",
"id": "underwriter",
"mode": "autonomous"
},
"sessionId": "sess_b0f9c646",
"traceId": "trace_41",
"actionType": "tool_call",
"action": "lookup_credit_file",
"surface": {
"plane": "action",
"adapter": "sdk"
},
"inputHash": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"outcome": "ok"
}
]
}x-ratelimit-limit—x-ratelimit-remaining—x-ratelimit-reset—
| Field | Type | Meaning |
|---|---|---|
acceptedrequired | integer | |
logIdrequired | string | The first event's log. |
headrequired | object | |
head.seqrequired | integer | |
head.hashrequired | string |
{
"accepted": 1,
"logId": "tenant_acme/prod",
"head": {
"seq": 4183,
"hash": "sha256:bb1074a2c9e1…"
}
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}Retry-After— Whole seconds until the window resets.x-ratelimit-limit— The ceiling.x-ratelimit-remaining— Always 0 here.x-ratelimit-reset— RFC 3339.
| Field | Type | Meaning |
|---|---|---|
errorrequired | "rate limited" | |
scoperequired | "ingest" | "decide" | "export" | |
limitrequired | integer | |
windowSecondsrequired | integer | |
retryAfterSecondsrequired | integer | |
resetAtrequired | string |
{
"error": "rate limited",
"scope": "decide",
"limit": 12000,
"windowSeconds": 60,
"retryAfterSeconds": 41,
"resetAt": "2026-08-20T10:01:00.000Z"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}POST/v1/ingest/{kind}/{vendor}Edge plane: a vendor's webhook, mapped onto the chainkey or webhook secret · details
ingestWebhookOne route per adapter kind rather than per vendor: the mapping differs, the schema does not. voice maps a finished call (lifecycle, per-turn decisions, tool calls, and a first-class disclosure event recording whether the AI disclosure was played); code maps a coding-agent session, with the commit as the effect-plane evidence; cloud maps a provider audit event (CloudTrail, GCP audit log, Kubernetes) as an effect. The vendor segment is recorded as surface.adapter and may be omitted, in which case it is the kind.
Authenticates with EITHER the bearer key OR the write-only webhook secret (x-auditant-webhook-secret, or x-vapi-secret because Vapi cannot be told otherwise). The secret can write events and do nothing else, so a vendor's webhook configuration screen never holds the key.
| Field | Type | Meaning |
|---|---|---|
kindrequiredpath | "voice" | "code" | "cloud" | Which adapter maps the payload. |
vendorrequiredpath | string | Recorded as `surface.adapter` — `vapi`, `retell`, `cursor`, `aws`… Free text. |
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
The vendor's payload, in the shape the adapter kind expects.
x-ratelimit-limit—x-ratelimit-remaining—x-ratelimit-reset—
| Field | Type | Meaning |
|---|---|---|
acceptedrequired | integer | Events written. |
logIdrequired | string | |
adapterrequired | string | The kind. |
vendorrequired | string |
{
"accepted": 7,
"logId": "tenant_acme/prod",
"adapter": "voice",
"vendor": "vapi"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string | |
supportedrequired | string[] |
{
"error": "unknown adapter \"sms\"",
"supported": [
"voice",
"code",
"cloud"
]
}Retry-After— Whole seconds until the window resets.x-ratelimit-limit— The ceiling.x-ratelimit-remaining— Always 0 here.x-ratelimit-reset— RFC 3339.
| Field | Type | Meaning |
|---|---|---|
errorrequired | "rate limited" | |
scoperequired | "ingest" | "decide" | "export" | |
limitrequired | integer | |
windowSecondsrequired | integer | |
retryAfterSecondsrequired | integer | |
resetAtrequired | string |
{
"error": "rate limited",
"scope": "decide",
"limit": 12000,
"windowSeconds": 60,
"retryAfterSeconds": 41,
"resetAt": "2026-08-20T10:01:00.000Z"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Policy1 endpoint · browse
The one synchronous call. It is on the request path on purpose.
POST/v1/decideAsk policy before actingtenant or admin key · details
decideSynchronous, on the request path by design, and judged in microseconds. The caller states what it is trying to do — that is genuinely its own knowledge. Everything the decision is checked against (spend inside the budget window, burn rate, session iterations, the halt flag, any real human approval) is derived from the chain and stored configuration, and overwrites anything the caller sent. evaluatedAgainst echoes those derived values so a caller can see what it was judged on.
An admin key is judged against the operator's custom rules; a tenant key against the built-in rules only — one tenant's policy must never govern another's agents. Without a budget store the route returns 501 rather than deciding on caller-supplied limits.
| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
agentIdrequired | string | |
actionrequired | string | |
amount | number | The value at stake, as the caller understands it. |
model | string | |
endUser | string | |
reason | string | The stated justification. Its presence is checked; its truth cannot be. |
sessionId | string | Needed for a human approval to be found — an approval is matched on session AND action. |
{
"logId": "tenant_acme/prod",
"agentId": "underwriter",
"action": "wire_transfer",
"amount": 50000,
"sessionId": "sess_b0f9c646",
"reason": "settling invoice #4471"
}x-ratelimit-limit—x-ratelimit-remaining—x-ratelimit-reset—
{
"effect": "pending_approval",
"policyId": "human-signoff-above-threshold",
"policyVersion": "1",
"engine": "auditant-cedar/1",
"reasons": [
"amount 50000 exceeds threshold 10000"
],
"evaluatedAgainst": {
"dailyTotal": 12.4,
"burnPerMin": 0.02,
"sessionIterations": 7,
"tenantHalted": false,
"approvalId": null
}
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}Retry-After— Whole seconds until the window resets.x-ratelimit-limit— The ceiling.x-ratelimit-remaining— Always 0 here.x-ratelimit-reset— RFC 3339.
| Field | Type | Meaning |
|---|---|---|
errorrequired | "rate limited" | |
scoperequired | "ingest" | "decide" | "export" | |
limitrequired | integer | |
windowSecondsrequired | integer | |
retryAfterSecondsrequired | integer | |
resetAtrequired | string |
{
"error": "rate limited",
"scope": "decide",
"limit": 12000,
"windowSeconds": 60,
"retryAfterSeconds": 41,
"resetAt": "2026-08-20T10:01:00.000Z"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Export1 endpoint · browse
The artifact an examiner receives — self-verifying, offline.
GET/v1/exportThe evidence bundletenant or admin key · details
exportBundleEverything needed to verify the record independently, in one file: the events in range, every checkpoint up to the head, the public keys, a plain README, and the standalone verifier itself as source — so checking the evidence needs Node and nothing else. Served as an attachment; it is meant to be handed to a person.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
fromquery | string | Inclusive, RFC 3339. Default: the beginning. |
toquery | string | Inclusive, RFC 3339. Default: now. |
Content-Disposition— `attachment; filename="auditant-<log>.json"`x-ratelimit-limit—x-ratelimit-remaining—x-ratelimit-reset—
| Field | Type | Meaning |
|---|---|---|
bundleVersionrequired | "1.0.0" | |
logIdrequired | string | |
fromrequired | string | |
torequired | string | |
exportedAtrequired | string | |
eventsrequired | AuditEvent[] | |
checkpointsrequired | SignedCheckpoint[] | |
checkpoints[].checkpointrequired | Checkpoint | |
checkpoints[].checkpoint.originrequired | string | `auditant.dev/<logId>` — namespaced so two deployments cannot collide. |
checkpoints[].checkpoint.treeSizerequired | integer | |
checkpoints[].checkpoint.headHashrequired | string | |
checkpoints[].checkpoint.timestamprequired | string | |
checkpoints[].bodyrequired | string | The exact bytes that were signed. |
checkpoints[].keyIdrequired | string | |
checkpoints[].signaturerequired | string | base64 ECDSA P-256 over `body`. |
checkpoints[].timestampToken | string | base64 RFC 3161 token, once an authority has countersigned. |
checkpoints[].wormAnchored | boolean | Operator-side: the copy landed in write-once storage. Not part of the signed body. |
publicKeysrequired | PublicKeyEntry[] | |
publicKeys[].keyIdrequired | string | `auditant-<12 hex of sha256(pem)>` — content-addressed. |
publicKeys[].pemrequired | string | SPKI PEM. |
publicKeys[].notBefore | string | |
publicKeys[].notAfter | string | |
startHead | ChainHead | |
startHead.logIdrequired | string | |
startHead.treeSizerequired | integer | |
startHead.headHashrequired | string | |
verifier | string | The standalone verifier as source — one dependency-free .mjs. Save it and run it with plain Node. |
readme | string | Added on export: how a stranger checks this bundle. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}Retry-After— Whole seconds until the window resets.x-ratelimit-limit— The ceiling.x-ratelimit-remaining— Always 0 here.x-ratelimit-reset— RFC 3339.
| Field | Type | Meaning |
|---|---|---|
errorrequired | "rate limited" | |
scoperequired | "ingest" | "decide" | "export" | |
limitrequired | integer | |
windowSecondsrequired | integer | |
retryAfterSecondsrequired | integer | |
resetAtrequired | string |
{
"error": "rate limited",
"scope": "decide",
"limit": 12000,
"windowSeconds": 60,
"retryAfterSeconds": 41,
"resetAt": "2026-08-20T10:01:00.000Z"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Reading the record6 endpoints · browse
Totals, pages, coverage and compliance, read off the same chained events.
GET/v1/eventsPage through a log by sequencetenant or admin key · details
listEventsEvents in sequence order, a page at a time. Ascending is the default for export-style walks; order=desc starts at the live head for console views. In either direction, pass a page's nextCursor back as cursor to continue without offsets, repeats, or gaps. A page can never exceed the maximum whatever is asked for, and nextCursor is null on the last page.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
cursorquery | string | A previous page's `nextCursor`. Ascending pages continue strictly after it; descending pages continue strictly before it. |
orderquery | "asc" | "desc" | Chain order. Use `desc` for a bounded view of the newest records. |
limitquery | integer | Page size. Above 1000 is a 400, not a silent clamp. |
sessionquery | string | Only this session. |
agentquery | string | Only this actor id. |
| Field | Type | Meaning |
|---|---|---|
eventsrequired | AuditEvent[] | |
limitrequired | integer | The page size that applied. |
nextCursorrequired | string | null | Pass back as `cursor` for the next page. `null` on the last page. |
orderrequired | "asc" | "desc" | The sequence order used for this page. |
{
"events": [
"…"
],
"limit": 200,
"nextCursor": "4382",
"order": "asc"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/statsTotals for one logtenant or admin key · details
statsAggregates the database computes: counts, spend, and how many model calls the upstream did not price — read from the attributionComplete flag, never inferred from a zero. Plus the head and the checkpoint count.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
eventsrequired | integer | |
agentsrequired | integer | Distinct actor ids. |
blockedrequired | integer | |
pendingApprovalrequired | integer | |
costTotalrequired | number | |
costIncompleterequired | integer | Events whose cost the upstream did not price. Never shown as $0. |
headrequired | object | |
head.treeSizerequired | integer | |
head.hashrequired | string | |
checkpointsrequired | integer |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/coverageThe completeness half of the evidence storytenant or admin key · details
coverageA hash chain proves what is on it was never altered; it cannot prove nothing was left off. This reading makes omission visible: which capture planes are live, which agents have gone quiet, whether traces are corroborated on a second plane, how fresh the anchors are — and one blunt score a buyer can watch go up. Computed over the newest window.cap events, and says so; events is the exact total from the head.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
computedAtrequired | string | |
eventsrequired | integer | Every event in the log — exact, from the head. |
windowrequired | ScanWindow | What a bounded reading actually read. When `truncated` is true the figures above it are floors. |
window.eventsrequired | integer | Events read. |
window.caprequired | integer | The cap that applied. |
window.truncatedrequired | boolean | More qualifying events exist than were read. |
window.fromSeqrequired | integer | null | |
window.toSeqrequired | integer | null | |
window.basisrequired | string | In words — `computed over the last 10,000 of 84,211 events`. |
planesLiverequired | "model" | "action" | "edge" | "effect"[] | |
agentsrequired | AgentCoverage[] | |
agents[].agentIdrequired | string | |
agents[].eventsrequired | integer | Within the window. |
agents[].lastSeenrequired | string | |
agents[].silenceMsrequired | integer | |
agents[].quietrequired | boolean | Silent for over 24h. A quiet agent and a broken emitter look identical from here. |
agents[].planesrequired | "model" | "action" | "edge" | "effect"[] | |
quietAgentsrequired | integer | |
joinedTracesrequired | integer | Traces observed on two or more planes — corroborated. |
totalTracesrequired | integer | |
unpricedEventsrequired | integer | |
pricedEventsrequired | integer | |
anchoringrequired | object | |
anchoring.checkpointsrequired | integer | |
anchoring.latestAtrequired | string | null | |
anchoring.ageMsrequired | integer | null | |
anchoring.stalerequired | boolean | |
anchoring.unanchoredTailrequired | integer | Events after the newest checkpoint — the current exposure. |
anchoring.timestampedrequired | integer | |
anchoring.wormAnchoredrequired | integer | |
scorerequired | integer | planes 35 · anchoring 25 · liveness 20 · join 10 · pricing 10. An empty log scores 0. |
findingsrequired | string[] | Every deduction, named. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/checkpointsThe seals, where they sit in the sequencetenant or admin key · details
checkpointsThe newest checkpoints on the log — up to window.cap of them, oldest first within that window, and window.total says how many there are. Each carries the tree size at signing; because event sequences are zero-based, it covers through sequence treeSize - 1. It also says when it was signed and which further assurances it has reached — an RFC 3161 countersignature and a copy in write-once storage. The signatures and tokens themselves travel in the evidence bundle.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
checkpointsrequired | object[] | |
checkpoints[].treeSizerequired | integer | The log's size when this seal was signed. It covers through zero-based event sequence `treeSize - 1`. |
checkpoints[].atrequired | string | When it was signed, RFC 3339. |
checkpoints[].countersignedrequired | boolean | An independent RFC 3161 timestamp authority has countersigned it. |
checkpoints[].wormrequired | boolean | A copy has landed in write-once storage. |
windowrequired | object | The bound on this read, disclosed. |
window.caprequired | integer | The most this read returns. |
window.returnedrequired | integer | |
window.totalrequired | integer | How many checkpoints the log holds. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/complianceWhat each regime asks, answered from the chaintenant or admin key · details
complianceEvery regime's obligations with a status each — satisfied, open, watching (a rule armed in monitor mode: recorded, deliberately not enforced) or outside (the record cannot answer it, and says so rather than implying otherwise) — and the open ones collapsed to the distinct actions that close them.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
computedAtrequired | string | |
regimesrequired | RegimeReport[] | |
regimes[].idrequired | string | |
regimes[].namerequired | string | |
regimes[].subrequired | string | Jurisdiction or scope. |
regimes[].obligationsrequired | Obligation[] | |
regimes[].obligations[].idrequired | string | |
regimes[].obligations[].clauserequired | string | As the standard numbers it. |
regimes[].obligations[].statementrequired | string | |
regimes[].obligations[].provesrequired | string | What in this product answers it. |
regimes[].obligations[].basisrequired | "record" | "configuration" | "outside" | |
regimes[].obligations[].statusrequired | "satisfied" | "open" | "watching" | "outside" | |
regimes[].obligations[].evidencerequired | integer[] | Sequence numbers that answer it. |
regimes[].obligations[].detailrequired | string | |
regimes[].obligations[].todo | string | |
regimes[].evidenceablerequired | integer | Obligations a record can answer at all — the denominator that means something. |
regimes[].satisfiedrequired | integer | |
regimes[].openrequired | integer | |
regimes[].watchingrequired | integer | |
regimes[].outsiderequired | integer | |
regimes[].evidenceEventsrequired | integer | |
evidenceablerequired | integer | |
satisfiedrequired | integer | |
openrequired | integer | |
outsiderequired | integer | |
actionsrequired | object[] | |
actions[].idrequired | string | |
actions[].todorequired | string | |
actions[].closesrequired | string[] | |
actions[].detailrequired | string | |
actions[].overduerequired | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/compliance/{regime}One regime, obligation by obligationtenant or admin key · details
regimeThe drill-in: one regime's obligations with the sequence numbers that answer each. Separate from the overview so a console that draws five summaries does not have to fetch every obligation of every regime to do it.
| Field | Type | Meaning |
|---|---|---|
regimerequiredpath | string | A regime id from the overview — `eu-ai-act`, `iso-42001`, `dpdp`, `soc2`, `nist-ai-rmf`… Unknown ids are a 404. |
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
idrequired | string | |
namerequired | string | |
subrequired | string | Jurisdiction or scope. |
obligationsrequired | Obligation[] | |
obligations[].idrequired | string | |
obligations[].clauserequired | string | As the standard numbers it. |
obligations[].statementrequired | string | |
obligations[].provesrequired | string | What in this product answers it. |
obligations[].basisrequired | "record" | "configuration" | "outside" | |
obligations[].statusrequired | "satisfied" | "open" | "watching" | "outside" | |
obligations[].evidencerequired | integer[] | Sequence numbers that answer it. |
obligations[].detailrequired | string | |
obligations[].todo | string | |
evidenceablerequired | integer | Obligations a record can answer at all — the denominator that means something. |
satisfiedrequired | integer | |
openrequired | integer | |
watchingrequired | integer | |
outsiderequired | integer | |
evidenceEventsrequired | integer |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Approvals3 endpoints · browse
The chain is the queue: a held action is a pending_approval event, and a human's answer is a human_override event in the same session.
GET/v1/approvalsOpen requeststenant or admin key · details
listApprovalsEvery pending_approval event with no later human_override in the same session naming the same action. Found by two indexed queries — never a scan of the log — newest first, capped at window.cap requests and saying so.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
pendingrequired | PendingApproval[] | Newest first. |
pending[].eventIdrequired | string | |
pending[].tsrequired | string | |
pending[].sessionId | string | |
pending[].agentIdrequired | string | |
pending[].actionrequired | string | |
pending[].reasonsrequired | string[] | |
pending[].approvalId | string | |
windowrequired | object | |
window.caprequired | integer | |
window.requestsrequired | integer | Held requests read. |
window.answersrequired | integer | `human_override` events read, from the oldest request onward. |
window.truncatedrequired | boolean | |
window.basisrequired | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}POST/v1/approvalsA human answers a held actiontenant or admin key · details
answerApprovalAppends a human_override event under the approver's name. Approval records outcome ok — the exact shape /v1/decide looks for, so the agent's next check walks through. Rejection records outcome blocked with a policy record naming the human, which the decision reader ignores — so the agent stays held, and the refusal is itself on the chain. An anonymous approval is exactly the record this product exists to prevent, so approver is required.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
sessionIdrequired | string | The session the request was held in. |
actionrequired | string | The held action, exactly as recorded. |
approverrequired | string | Who is answering. Recorded as the actor. |
approverequired | boolean | |
reason | string |
{
"log": "tenant_acme/prod",
"sessionId": "sess_b0f9c646",
"action": "wire_transfer",
"approver": "augusta",
"approve": false,
"reason": "amount not justified by the campaign plan"
}| Field | Type | Meaning |
|---|---|---|
okrequired | true | |
eventIdrequired | string | The `human_override` event written. |
approvedrequired | boolean |
{
"ok": true,
"eventId": "evt_approval_k2x9q1",
"approved": false
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/approvals/clickOne-click answer from a Slack linksigned link · details
clickApprovalThe one route that serves markup and sits before the bearer gate: the clicker is a human in a browser, and the signed, expiring token in t IS the credential. Records the answer exactly as POST /v1/approvals would, under the configured approver label, and renders a sentence. Everything interpolated into the page is escaped — the action name is authored by the agents this product audits. 404 when one-click links are not configured (no link secret); 403 for an invalid or expired token; 200 "Already answered" when someone got there first.
| Field | Type | Meaning |
|---|---|---|
trequiredquery | string | The HMAC-signed, expiring token from the Slack message. |
Ledger3 endpoints · browse
Spend, computed from the chain rather than rented from a gateway.
GET/v1/ledgerSpend analysis for one logtenant or admin key · details
ledgerCost per agent, customer, model and run, and cost per clean run — the one that completed with no block and no human. Administration (sign-ins, rule and budget changes) is in the chain and excluded from spend. Unpriced calls are counted, never folded in as $0. Computed over the newest window.cap events in range; narrow from/to when window.truncated is true.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
fromquery | string | |
toquery | string |
| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
fromrequired | string | |
torequired | string | |
totalUsdrequired | number | |
breakdownrequired | object | |
breakdown.input | number | |
breakdown.output | number | |
breakdown.reasoning | number | |
breakdown.cacheRead | number | |
breakdown.cacheCreation | number | |
breakdown.toolUsage | number | |
runsrequired | integer | |
cleanRunsrequired | integer | |
costPerCleanRunrequired | number | null | Null when there were no clean runs — never Infinity or NaN. |
unpricedCallsrequired | integer | |
byAgentrequired | object[] | |
byAgent[].agentId | string | |
byAgent[].costUsd | number | |
byAgent[].runs | integer | |
byAgent[].blocked | integer | |
byCustomerrequired | object[] | |
byCustomer[].customer | string | |
byCustomer[].costUsd | number | |
byCustomer[].runs | integer | |
byModelrequired | object[] | |
byModel[].model | string | |
byModel[].costUsd | number | |
byModel[].calls | integer | |
windowrequired | ScanWindow | What a bounded reading actually read. When `truncated` is true the figures above it are floors. |
window.eventsrequired | integer | Events read. |
window.caprequired | integer | The cap that applied. |
window.truncatedrequired | boolean | More qualifying events exist than were read. |
window.fromSeqrequired | integer | null | |
window.toSeqrequired | integer | null | |
window.basisrequired | string | In words — `computed over the last 10,000 of 84,211 events`. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/ledger/runsUnit economics, per runtenant or admin key · details
ledgerRunsOne row per session: calls, cost, whether policy stopped anything, whether a human had to step in. Bounded like the summary.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
fromquery | string | |
toquery | string |
| Field | Type | Meaning |
|---|---|---|
runsrequired | RunCost[] | |
runs[].sessionIdrequired | string | |
runs[].agentIdrequired | string | |
runs[].customerrequired | string | null | |
runs[].llmCallsrequired | integer | |
runs[].toolCallsrequired | integer | |
runs[].costUsdrequired | number | |
runs[].costTrustworthyrequired | boolean | False when any model call in the run priced as unknown. |
runs[].startedAtrequired | string | |
runs[].endedAtrequired | string | |
runs[].hitPolicyrequired | boolean | |
runs[].neededHumanrequired | boolean | |
runs[].cleanOutcomerequired | boolean | |
windowrequired | ScanWindow | What a bounded reading actually read. When `truncated` is true the figures above it are floors. |
window.eventsrequired | integer | Events read. |
window.caprequired | integer | The cap that applied. |
window.truncatedrequired | boolean | More qualifying events exist than were read. |
window.fromSeqrequired | integer | null | |
window.toSeqrequired | integer | null | |
window.basisrequired | string | In words — `computed over the last 10,000 of 84,211 events`. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/ledger/budgetBudget state for one agenttenant or admin key · details
ledgerBudgetSpend since since, burn rate, and whether it exceeded ceiling. The spend is one aggregate the database computes over an indexed column — exact whatever the log size. Note this is a calculator against a ceiling you pass; the ceilings a decision is actually judged against live in /v1/budgets.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
agentrequiredquery | string | |
sincequery | string | Window start. Default: 24 hours ago. |
ceilingquery | number | USD. |
| Field | Type | Meaning |
|---|---|---|
agentIdrequired | string | |
windowStartrequired | string | |
spentUsdrequired | number | |
ceilingUsdrequired | number | |
remainingUsdrequired | number | Clamped at zero. |
utilisationrequired | number | |
burnRatePerMinrequired | number | |
exceededrequired | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Budgets3 endpoints · browse
Ceilings and the halt flag — configuration a caller can never assert, only an admin can set.
GET/v1/budgetsConfigured ceilings, and the halt flagtenant or admin key · details
listBudgetsAn admin sees every budget scope. A tenant sees its own halt state and an empty budgets list — ceilings are the operator's configuration.
| Field | Type | Meaning |
|---|---|---|
logquery | string | Required for a tenant key; optional for an admin (then `halted` is for the empty log). |
| Field | Type | Meaning |
|---|---|---|
budgetsrequired | Budget[] | |
budgets[].scoperequired | string | An agent id, or `*` for the fleet default. |
budgets[].ceilingUsdrequired | number | |
budgets[].windowHoursrequired | integer | |
budgets[].updatedAtrequired | string | |
budgets[].updatedByrequired | string | |
haltedrequired | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}PUT/v1/budgetsSet a ceilingadmin key · details
setBudgetUpserts the budget for a scope — an agent id, or * for the fleet default — and records the change on the chain under author. "Who raised the ceiling the day before the overspend" is a question that gets asked.
| Field | Type | Meaning |
|---|---|---|
scope | string | An agent id, or `*`. |
ceilingUsdrequired | number | |
windowHours | integer | |
authorrequired | string | |
log | string | The log this belongs to and is chained on. Defaults to the operator's own log; a tenant key may name only its own. |
{
"scope": "underwriter",
"ceilingUsd": 250,
"windowHours": 24,
"author": "augusta"
}| Field | Type | Meaning |
|---|---|---|
budgetrequired | Budget | |
budget.scoperequired | string | An agent id, or `*` for the fleet default. |
budget.ceilingUsdrequired | number | |
budget.windowHoursrequired | integer | |
budget.updatedAtrequired | string | |
budget.updatedByrequired | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/haltThe kill switchtenant or admin key · details
haltSets the halt flag for a log. While halted, every decision for that log is refused. A tenant may pull its own switch — that is the control, not a privilege — but only its own. Recorded on the chain with a name attached; it is the most consequential button in the product and the one most likely to be pressed in a hurry.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
haltedrequired | boolean | |
authorrequired | string |
{
"log": "tenant_acme/prod",
"halted": true,
"author": "augusta"
}| Field | Type | Meaning |
|---|---|---|
okrequired | true | |
haltedrequired | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Rules5 endpoints · browse
Customer-defined rules, versioned by content hash, never deleted.
GET/v1/policiesWhat is armed, in plain Englishtenant or admin key · details
listPoliciesEvery rule the engine evaluates, described. An admin sees the built-ins plus the operator's custom rules and whether custom rules are configured at all; a tenant sees the built-ins that actually govern its decisions and customRulesEnabled: false.
| Field | Type | Meaning |
|---|---|---|
logquery | string | The log whose rules to read. A tenant key may name only its own; the operator's key defaults to the operator's own log. |
| Field | Type | Meaning |
|---|---|---|
policiesrequired | PolicyDescription[] | |
policies[].idrequired | string | |
policies[].englishrequired | string | |
policies[].enforcingrequired | boolean | False ⇒ monitor mode. |
policies[].descriptionrequired | string | |
policies[].versionrequired | string | |
policies[].builtInrequired | boolean | Built-ins cannot be edited or retired. |
customRulesEnabledrequired | boolean | Whether a rule store is configured on this plane — distinct from "no custom rules yet". |
customrequired | StoredRule[] | |
custom[].specrequired | RuleSpec | |
custom[].spec.idrequired | string | |
custom[].spec.descriptionrequired | string | |
custom[].spec.effectrequired | "deny" | "pending_approval" | |
custom[].spec.conditionrequired | object | object | object | object | A boolean tree over the decision context. Nesting is limited to 8 levels. |
custom[].spec.monitorModerequired | boolean | Rules ship watching. Arming is a deliberate, separately recorded act. |
custom[].versionrequired | string | The content hash of the spec. |
custom[].englishrequired | string | The rule, as a sentence. |
custom[].createdAtrequired | string | |
custom[].createdByrequired | string | |
custom[].retiredAtrequired | string | null |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}PUT/v1/policiesSave a rule, as a new versionadmin key · details
putPolicyValidates the spec, retires whatever version of that rule id was live, and stores this one. The version is the content hash, so saving the same spec twice is a no-op that returns the existing version. Every change is itself an event on the chain, carrying both sides in plain English. A validation failure names the path — condition.all[1]: gt needs a number, got string.
| Field | Type | Meaning |
|---|---|---|
rulerequired | RuleSpec | |
rule.idrequired | string | |
rule.descriptionrequired | string | |
rule.effectrequired | "deny" | "pending_approval" | |
rule.conditionrequired | object | object | object | object | A boolean tree over the decision context. Nesting is limited to 8 levels. |
rule.monitorModerequired | boolean | Rules ship watching. Arming is a deliberate, separately recorded act. |
authorrequired | string | |
log | string | The log this belongs to and is chained on. Defaults to the operator's own log; a tenant key may name only its own. |
{
"rule": {
"id": "wire-limit-emea",
"description": "Wires above €25k wait for a human",
"effect": "pending_approval",
"condition": {
"all": [
{
"field": "action",
"op": "eq",
"value": "wire_transfer"
},
{
"field": "amount",
"op": "gt",
"value": 25000
}
]
},
"monitorMode": true
},
"author": "augusta"
}| Field | Type | Meaning |
|---|---|---|
rulerequired | StoredRule | |
rule.specrequired | RuleSpec | |
rule.spec.idrequired | string | |
rule.spec.descriptionrequired | string | |
rule.spec.effectrequired | "deny" | "pending_approval" | |
rule.spec.conditionrequired | object | object | object | object | A boolean tree over the decision context. Nesting is limited to 8 levels. |
rule.spec.monitorModerequired | boolean | Rules ship watching. Arming is a deliberate, separately recorded act. |
rule.versionrequired | string | The content hash of the spec. |
rule.englishrequired | string | The rule, as a sentence. |
rule.createdAtrequired | string | |
rule.createdByrequired | string | |
rule.retiredAtrequired | string | null |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string | |
path | string |
{
"error": "gt needs a number, got string (at condition.all[1])",
"path": "condition.all[1]"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/policies/{ruleId}/historyEvery version of a ruleadmin key · details
policyHistoryNewest first. Nothing is ever deleted: a rule that governed a real decision is part of that decision's evidence.
| Field | Type | Meaning |
|---|---|---|
ruleIdrequiredpath | string | |
logquery | string | The log whose rules to read. A tenant key may name only its own; the operator's key defaults to the operator's own log. |
| Field | Type | Meaning |
|---|---|---|
ruleIdrequired | string | |
versionsrequired | StoredRule[] | |
versions[].specrequired | RuleSpec | |
versions[].spec.idrequired | string | |
versions[].spec.descriptionrequired | string | |
versions[].spec.effectrequired | "deny" | "pending_approval" | |
versions[].spec.conditionrequired | object | object | object | object | A boolean tree over the decision context. Nesting is limited to 8 levels. |
versions[].spec.monitorModerequired | boolean | Rules ship watching. Arming is a deliberate, separately recorded act. |
versions[].versionrequired | string | The content hash of the spec. |
versions[].englishrequired | string | The rule, as a sentence. |
versions[].createdAtrequired | string | |
versions[].createdByrequired | string | |
versions[].retiredAtrequired | string | null |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/policies/{ruleId}/versions/{version}One exact versionadmin key · details
policyVersionThe lookup the whole rule store exists for: turns the policyId and policyVersion on a nine-month-old decision back into the rule that made it, in the words it was written in.
| Field | Type | Meaning |
|---|---|---|
ruleIdrequiredpath | string | |
versionrequiredpath | string | The content hash, as recorded on the decision. |
logquery | string | The log whose rules to read. A tenant key may name only its own; the operator's key defaults to the operator's own log. |
| Field | Type | Meaning |
|---|---|---|
rulerequired | StoredRule | |
rule.specrequired | RuleSpec | |
rule.spec.idrequired | string | |
rule.spec.descriptionrequired | string | |
rule.spec.effectrequired | "deny" | "pending_approval" | |
rule.spec.conditionrequired | object | object | object | object | A boolean tree over the decision context. Nesting is limited to 8 levels. |
rule.spec.monitorModerequired | boolean | Rules ship watching. Arming is a deliberate, separately recorded act. |
rule.versionrequired | string | The content hash of the spec. |
rule.englishrequired | string | The rule, as a sentence. |
rule.createdAtrequired | string | |
rule.createdByrequired | string | |
rule.retiredAtrequired | string | null |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}DELETE/v1/policies/{ruleId}Retire a ruleadmin key · details
retirePolicyStops the rule being evaluated. Its history stays. 404 when nothing by that id is live — retiring twice would record two retirements and report the second one's answer.
| Field | Type | Meaning |
|---|---|---|
ruleIdrequiredpath | string | |
authorrequiredquery | string | |
logquery | string | The log whose rules to read. A tenant key may name only its own; the operator's key defaults to the operator's own log. |
| Field | Type | Meaning |
|---|---|---|
okrequired | true |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
okrequired | false |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Verify2 endpoints · browse
Verification and public keys — so anyone can check a bundle without asking us.
GET/v1/keysPublic keystenant or admin key · details
publicKeysEvery checkpoint-signing key this plane has published, so anyone holding a bundle can verify it without asking us. Key ids are content-addressed: two different keys cannot collide on one id, and a rotation never overwrites the key that signed older checkpoints.
| Field | Type | Meaning |
|---|---|---|
keysrequired | PublicKeyEntry[] | |
keys[].keyIdrequired | string | `auditant-<12 hex of sha256(pem)>` — content-addressed. |
keys[].pemrequired | string | SPKI PEM. |
keys[].notBefore | string | |
keys[].notAfter | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}POST/v1/verifyVerify a bundle someone sent backadmin key · details
verifyBundleThe same verifier an auditor runs from the CLI and the same one embedded in every bundle, reached over HTTP so the operator console does not carry a second copy. Read-only and stateless: nothing is stored, nothing is appended. Admin only, purely because it is an unbounded parse of caller-supplied JSON. A malformed bundle is a 400, not a verification failure — "that is not a bundle" and "this record was altered" are different findings, and reporting the first as the second would be an accusation.
| Field | Type | Meaning |
|---|---|---|
bundleVersionrequired | "1.0.0" | |
logIdrequired | string | |
fromrequired | string | |
torequired | string | |
exportedAtrequired | string | |
eventsrequired | AuditEvent[] | |
checkpointsrequired | SignedCheckpoint[] | |
checkpoints[].checkpointrequired | Checkpoint | |
checkpoints[].checkpoint.originrequired | string | `auditant.dev/<logId>` — namespaced so two deployments cannot collide. |
checkpoints[].checkpoint.treeSizerequired | integer | |
checkpoints[].checkpoint.headHashrequired | string | |
checkpoints[].checkpoint.timestamprequired | string | |
checkpoints[].bodyrequired | string | The exact bytes that were signed. |
checkpoints[].keyIdrequired | string | |
checkpoints[].signaturerequired | string | base64 ECDSA P-256 over `body`. |
checkpoints[].timestampToken | string | base64 RFC 3161 token, once an authority has countersigned. |
checkpoints[].wormAnchored | boolean | Operator-side: the copy landed in write-once storage. Not part of the signed body. |
publicKeysrequired | PublicKeyEntry[] | |
publicKeys[].keyIdrequired | string | `auditant-<12 hex of sha256(pem)>` — content-addressed. |
publicKeys[].pemrequired | string | SPKI PEM. |
publicKeys[].notBefore | string | |
publicKeys[].notAfter | string | |
startHead | ChainHead | |
startHead.logIdrequired | string | |
startHead.treeSizerequired | integer | |
startHead.headHashrequired | string | |
verifier | string | The standalone verifier as source — one dependency-free .mjs. Save it and run it with plain Node. |
readme | string | Added on export: how a stranger checks this bundle. |
| Field | Type | Meaning |
|---|---|---|
okrequired | boolean | |
assurancerequired | "broken" | "unanchored" | "signed" | "timestamped" | Worst-first. `unanchored` is internally consistent but externally unproven. |
chainrequired | object | |
chain.okrequired | boolean | |
chain.verifiedrequired | integer | Events verified before the first failure, or in total. |
chain.head | ChainHead | |
chain.head.logIdrequired | string | |
chain.head.treeSizerequired | integer | |
chain.head.headHashrequired | string | |
chain.failuresrequired | object[] | |
chain.failures[].namerequired | string | |
chain.failures[].messagerequired | string | Names the sequence number. |
checkpointsrequired | object[] | |
checkpoints[].treeSizerequired | integer | |
checkpoints[].verificationrequired | object | |
checkpoints[].verification.okrequired | boolean | |
checkpoints[].verification.signatureValidrequired | boolean | |
checkpoints[].verification.bodyMatchesrequired | boolean | |
checkpoints[].verification.timestamped | boolean | |
checkpoints[].verification.reasonsrequired | string[] | |
checkpoints[].coversChainrequired | boolean | The checkpoint's head matches the recomputed chain at that size. |
anchoredThroughSeqrequired | integer | Events at or below this sequence are anchored. -1 when none are. |
summaryrequired | string[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Tenants3 endpoints · browse
Self-serve provisioning and key minting. Provisioning never returns a key.
POST/v1/tenantsEnsure a tenant existsadmin key · details
provisionTenantIdempotent. The log id is derived from the email (t_<12 hex>/prod) — deterministic so a re-provision lands on the same log, opaque so it reveals nothing about the address. Never returns a key: creating the tenant and minting a credential are different acts with different audiences.
| Field | Type | Meaning |
|---|---|---|
emailrequired | string |
{
"email": "alice@example.com"
}| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
createdrequired | boolean | True when this call created the tenant. |
{
"logId": "t_5c1b2a9e4f07/prod",
"created": true
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/tenants/keyMint a tenant key, revoking every earlier oneadmin key · details
mintKeyThe plaintext key exists in this response and nowhere else — it is stored only as SHA-256. Revocation-on-mint is the point: one tenant, one live key, always. A tenant key cannot mint, including its own, because a leaked key that could rotate itself would be unrevokable by the person it was stolen from.
| Field | Type | Meaning |
|---|---|---|
emailrequired | string |
| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
apiKeyrequired | string |
{
"logId": "t_5c1b2a9e4f07/prod",
"apiKey": "ak_…48 hex…"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/tenants/meA tenant key introspects itselftenant key only · details
whoAmIOnly a tenant key: an admin key is not a tenant and gets a 403 that says so.
| Field | Type | Meaning |
|---|---|---|
logIdrequired | string | |
emailrequired | string | null | |
hasLiveKeyrequired | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "only a tenant key can introspect itself"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Operator3 endpoints · browse
Reads across every tenant. Admin only, and never a secret.
GET/v1/admin/overviewEvery log, in one queryadmin key · details
adminOverviewPer-log totals, head, anchoring state, tenant email and halt flag, plus computed findings — each naming the log and the threshold it crossed. Provisioned tenants that have not sent an event yet are included; omitting them would make the console report a smaller, healthier deployment than the real one.
| Field | Type | Meaning |
|---|---|---|
generatedAtrequired | string | |
logsrequired | LogSummary[] | |
logs[].logIdrequired | string | |
logs[].eventsrequired | integer | |
logs[].agentsrequired | integer | |
logs[].blockedrequired | integer | |
logs[].pendingApprovalrequired | integer | |
logs[].costTotalrequired | number | |
logs[].costIncompleterequired | integer | |
logs[].headSeqrequired | integer | null | |
logs[].headHashrequired | string | null | |
logs[].checkpointsrequired | integer | |
logs[].unanchoredTailrequired | integer | |
logs[].lastCheckpointAtrequired | string | null | |
logs[].timestampedrequired | integer | |
logs[].wormAnchoredrequired | integer | |
logs[].emailrequired | string | null | |
logs[].haltedrequired | boolean | |
totalsrequired | object | |
totals.logs | integer | |
totals.events | integer | |
totals.agents | integer | |
totals.blocked | integer | |
totals.pendingApproval | integer | |
totals.costTotal | number | |
totals.costIncomplete | integer | |
totals.unanchoredTail | integer | |
findingsrequired | string[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/admin/tenantsWho is here, and whether they can writeadmin key · details
adminTenantsKey state, never a key or a key hash. A console that could read out a credential would make everyone with console access able to impersonate any tenant.
| Field | Type | Meaning |
|---|---|---|
tenantsrequired | TenantSummary[] | |
tenants[].logIdrequired | string | |
tenants[].emailrequired | string | |
tenants[].createdAtrequired | integer | Epoch milliseconds. |
tenants[].hasLiveKeyrequired | boolean | |
tenants[].keysIssuedrequired | integer |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/admin/healthWhat the plane is configured to do, and whether it is doing itadmin key · details
adminHealthThree states, not two: off (deliberately disabled) and degraded (configured and failing) are different facts, and collapsing them trains an operator to ignore the indicator.
| Field | Type | Meaning |
|---|---|---|
checksrequired | object[] | |
checks[].idrequired | "signing-key" | "checkpointer" | "timestamp-authority" | "object-lock" | "api-keys" | "slack" | |
checks[].labelrequired | string | |
checks[].staterequired | "ok" | "degraded" | "off" | |
checks[].detailrequired | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Capture1 endpoint · browse
POST/v1/tracesRaw OTLP/HTTP traces — the zero-SDK pathkey or webhook secret · details
ingestOtlpThe standard OTLP traces path, so OTEL_EXPORTER_OTLP_ENDPOINT=<this plane> is the whole exporter configuration. Accepts protobuf or JSON, gzip or deflate (inflated body capped at 64 MB → 413). Authenticates with a bearer key OR the write-only webhook secret. The log comes from x-auditant-log, ?log=, the resource attribute auditant.log_id, or — for a tenant key — the key itself, then the same scoping rule as /v1/events. Spans are mapped through the same OpenInference/GenAI mapper as the SDKs; spans that are not evidence are read and not recorded, which is not a rejection.
| Field | Type | Meaning |
|---|---|---|
logquery | string | The log to write, when not given as a header or resource attribute. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}Retry-After— Whole seconds until the window resets.x-ratelimit-limit— The ceiling.x-ratelimit-remaining— Always 0 here.x-ratelimit-reset— RFC 3339.
| Field | Type | Meaning |
|---|---|---|
errorrequired | "rate limited" | |
scoperequired | "ingest" | "decide" | "export" | |
limitrequired | integer | |
windowSecondsrequired | integer | |
retryAfterSecondsrequired | integer | |
resetAtrequired | string |
{
"error": "rate limited",
"scope": "decide",
"limit": 12000,
"windowSeconds": 60,
"retryAfterSeconds": 41,
"resetAt": "2026-08-20T10:01:00.000Z"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Billing6 endpoints · browse
POST/v1/billing/webhook/razorpayRazorpay's word — HMAC over the raw bodykey or webhook secret · details
razorpayWebhookNo bearer: the request carries x-razorpay-signature, an HMAC-SHA256 over the raw body, verified in constant time against the configured secret(s). Redeliveries are idempotent by x-razorpay-event-id; a delivery whose apply failed releases its claim so the retry lands. Every plan transition is a chained event on the tenant's log.
| Field | Type | Meaning |
|---|---|---|
ok | boolean | |
applied | boolean | |
outcome | string | applied | stale | unmatched | ignored |
duplicate | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/billingThe band, the agents counted against it, cap state, invoicestenant or admin key · details
billingSummaryPlan, period, agent usage vs cap, cap state, subscription and invoices for one log. Never a gate on the record: at or past the cap the plane still accepts every event. sync=1 asks the provider for the live subscription before answering.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
syncquery | string | `1` to refresh from the provider first. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/billing/checkoutBuy Team or Scale — the provider's hosted page, never a card formtenant or admin key · details
startCheckoutCreates the subscription at the provider and returns its hosted checkout page. The operator's own log is never billed (400); a log with a live subscription is told to change plan instead (409).
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
planrequired | "team" | "scale" | |
currency | string | USD or INR |
email | string | |
authorrequired | string | The person acting, recorded on the chain. |
| Field | Type | Meaning |
|---|---|---|
subscriptionId | string | |
checkoutUrl | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/billing/changeMove to another bandtenant or admin key · details
changePlanUpgrades take effect now; downgrades are scheduled for the cycle end. Chained under the author.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
planrequired | "team" | "scale" | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
ok | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/billing/cancelEnd the paid plan at the cycle endtenant or admin key · details
cancelPlanThe record stays exportable; the log returns to Self-serve when the cycle ends.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
ok | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/billing/grantSet a plan by hand — pilot, bank transfer, enterprise paperadmin key · details
grantPlanAdmin only: a tenant key that could grant itself Enterprise would make the price a suggestion. Chained on the tenant's log under the author.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
planrequired | "free" | "team" | "scale" | "enterprise" | |
until | string | RFC 3339 or epoch ms; null/absent = open-ended |
note | string | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
ok | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Seats6 endpoints · browse
POST/v1/members/resolveWhich log and seat a verified email lands onadmin key · details
resolveSeatAdmin only — the dashboard's server asks on every request. Pending invitations are accepted; a listed operator (operatorLog) is seated as owner of the deployment's log; otherwise the newest seat wins; otherwise a fresh tenant is provisioned and its first sign-in is its owner. Every seat change is a chained event.
| Field | Type | Meaning |
|---|---|---|
emailrequired | string | |
operatorLog | string | The deployment's own log, when the email is on the dashboard's operator list. |
| Field | Type | Meaning |
|---|---|---|
logId | string | |
role | "owner" | "approver" | "auditor" | |
can | object | |
created | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/membersWho holds which seat on a logadmin key · details
listMembersAdmin only; author must hold a seat (read) on the log. Members and pending invitations (14-day expiry).
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
authorrequiredquery | string | The seated person asking. |
| Field | Type | Meaning |
|---|---|---|
members | object[] | |
members[].logId | string | |
members[].email | string | |
members[].role | "owner" | "approver" | "auditor" | |
members[].grantedAt | string | |
members[].grantedBy | string | |
invites | object[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}DELETE/v1/membersRemove someone's seatadmin key · details
revokeSeatOwner only (the author). A log keeps at least one owner. Chained under the author before the row changes.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
emailrequiredquery | string | Whose seat. |
authorrequiredquery | string | The owner acting. |
| Field | Type | Meaning |
|---|---|---|
ok | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}POST/v1/members/invitesInvite someone to a seatadmin key · details
inviteOwner only. Chained under the inviter the moment it is issued; the invitee is seated on their first verified sign-in within 14 days.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
emailrequired | string | |
rolerequired | "owner" | "approver" | "auditor" | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
invite | object |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}DELETE/v1/members/invites/{inviteId}Withdraw an invitationadmin key · details
revokeInviteOwner only. Chained under the author.
| Field | Type | Meaning |
|---|---|---|
inviteIdrequiredpath | string | From the roster. |
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
authorrequiredquery | string | The owner acting. |
| Field | Type | Meaning |
|---|---|---|
ok | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}POST/v1/members/grantsMove an existing member to a different seatadmin key · details
changeRoleOwner only; the last owner cannot be demoted. Chained under the author before the row changes.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
emailrequired | string | |
rolerequired | "owner" | "approver" | "auditor" | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
member | object | |
member.logId | string | |
member.email | string | |
member.role | "owner" | "approver" | "auditor" | |
member.grantedAt | string | |
member.grantedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}Lifecycle7 endpoints · browse
GET/v1/lifecycleRetention, legal hold, and the price tables in forcetenant or admin key · details
lifecycleConfigThe log's retention schedule (null = keep forever), whether a legal hold suspends every purge and erasure, and the versioned price tables.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
logId | string | |
retentionDays | integer | |
legalHold | boolean | |
holdReason | string | |
updatedAt | string | |
updatedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}PUT/v1/lifecycle/retentionHow long payloads are keptadmin key · details
setRetentionAdmin only. Whole days (1–36,500) or null to keep forever. Both sides of the change are chained under the author. Events and hashes are never purged — only payload content.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
days | integer | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
config | object | |
config.logId | string | |
config.retentionDays | integer | |
config.legalHold | boolean | |
config.holdReason | string | |
config.updatedAt | string | |
config.updatedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}PUT/v1/lifecycle/holdPlace or release a legal holdadmin key · details
setLegalHoldAdmin only. While held, retention purges are suspended and explicit erasure is refused (409). Placement and release are chained with the reason.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
holdrequired | boolean | |
reason | string | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
config | object | |
config.logId | string | |
config.retentionDays | integer | |
config.legalHold | boolean | |
config.holdReason | string | |
config.updatedAt | string | |
config.updatedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/lifecycle/eraseTombstone payload content by hash — the chain staysadmin key · details
erasePayloadsAdmin only. Records a chained payload_erased event naming the actor and reason FIRST, then destroys the content. Hashes and events remain, so the bundle still verifies and the verifier reports the erasure. A hash never held here is still tombstoned (Mode B custody). Refused under legal hold.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
hashesrequired | string[] | |
actorrequired | string | |
reasonrequired | string | |
subject | string | The data subject, if any. |
| Field | Type | Meaning |
|---|---|---|
ok | boolean | |
logId | string | |
erased | string[] | |
alreadyErased | string[] | |
eventIds | string[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/lifecycle/purgeRun the retention purge nowadmin key · details
purgeNowAdmin only. For one log or every log with a schedule. Records the purge on the chain before destroying anything; skips logs under hold.
| Field | Type | Meaning |
|---|---|---|
log | string | Omit to purge every scheduled log. |
| Field | Type | Meaning |
|---|---|---|
results | object[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/lifecycle/payloadA payload this log holds, by hashtenant or admin key · details
getPayloadScoped by log in the query itself — another log's copy of the same bytes is not this log's payload.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
hashrequiredquery | string | sha256:<64 hex> |
| Field | Type | Meaning |
|---|---|---|
hash | string | |
logId | string | |
body | string | |
storedAt | string | |
erasedAt | string | |
erasedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}PUT/v1/lifecycle/payloadHold a payload, content-addressedtenant or admin key · details
putPayloadThe content must hash to the given key. Re-storing an erased hash is refused (409). Keyed by (log, hash).
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
hashrequired | string | |
bodyrequired | string |
| Field | Type | Meaning |
|---|---|---|
hash | string | |
stored | boolean | |
deduplicated | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Readings11 endpoints · browse
POST/v1/policies/simulateReplay the record through a draft ruleadmin key · details
simulatePolicyAdmin only, reads only. The draft is validated like a saved rule, then evaluated by the SAME matcher the live engine runs against the newest window of the log (up to 100,000 events). Returns would-have-blocked / would-have-held counts with the exact events, what was already stopped, and caveats (context fields the record never carried are blind spots, not zero hits).
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
rulerequired | object | A RuleSpec, as for PUT /v1/policies. |
limit | integer | Events to replay, newest first (default 500). |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/agentsEvery agent the log has heard fromtenant or admin key · details
agentIndexOne row per agent id: planes seen, action and tool counts, spend (a floor when unpriced), last seen, quiet/live. Read from the newest window of the chain.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
agents | object[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/agents/{agentId}One agent's cardtenant or admin key · details
agentCardPlanes, actions, tools called, models, spend, the rules that bind it (three-valued: binds / cannot / would need a field the record lacks), sessions, effective budget, and its drift reading.
| Field | Type | Meaning |
|---|---|---|
agentIdrequiredpath | string | The actor id as recorded. |
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/discoveryActors heard from that nobody introducedtenant or admin key · details
discoveryNever-seen actor ids, gateway-seen agents with no SDK session, and OTel services emitting without a registration — from the chain only. No device sensor and no network tap: an agent that never reached this plane is not here.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/readinessPer-regime readiness, denominator attachedtenant or admin key · details
readinessFor each compliance regime: satisfied / evidenceable / watching / outside, the percentage (null when nothing is evidenceable), and the open obligations with their todo. Arithmetic over compliance(), never a vanity score.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/driftBehaviour against each agent's own baselinetenant or admin key · details
driftPer agent: an action-profile baseline over a trailing window and today's deviations (new action, plane gone, volume collapse or burst) as findings with deductions. Signalling, not intervention — and an agent with no actions today is quiet, not drifting.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/packsRegulation-mapped rule setsadmin key · details
listPacksAdmin only. Each pack (EU AI Act Art 12, FINRA supervision, Colorado SB 26-189 …) with its rules and whether each is already installed.
| Field | Type | Meaning |
|---|---|---|
logquery | string | The log whose rules to read. A tenant key may name only its own; the operator's key defaults to the operator's own log. |
| Field | Type | Meaning |
|---|---|---|
packs | object[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}POST/v1/packs/{packId}/installInstall a pack, every rule in monitor modeadmin key · details
installPackAdmin only. Each rule goes through the rule store like a hand-written one — chained under the author, monitor mode forced, an existing rule id never overwritten.
| Field | Type | Meaning |
|---|---|---|
packIdrequiredpath | string | A pack id from GET /v1/packs. |
| Field | Type | Meaning |
|---|---|---|
authorrequired | string | |
log | string | The log this belongs to and is chained on. Defaults to the operator's own log; a tenant key may name only its own. |
| Field | Type | Meaning |
|---|---|---|
installed | string[] | |
skipped | string[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/trustThis log's public trust page configurationtenant or admin key · details
getTrustPageThe slug, whether it is public, and which sections it shows. Nothing here is a figure — the figures are read when the page is.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
page | object | |
page.logId | string | |
page.slug | string | |
page.public | boolean | |
page.label | string | |
page.sections | string[] | |
page.updatedAt | string | |
page.updatedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}PUT/v1/trustPublish, unpublish, retitle or scope the pagetenant or admin key · details
setTrustPageSlug ^[a-z0-9][a-z0-9-]{1,39}$. The flip is chained under the author BEFORE the row changes; a no-op patch chains nothing. A slug another log holds is refused (409-class 400 with path).
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
public | boolean | |
slug | string | |
label | string | |
sections | string[] | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
page | object | |
page.logId | string | |
page.slug | string | |
page.public | boolean | |
page.label | string | |
page.sections | string[] | |
page.updatedAt | string | |
page.updatedBy | string |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}GET/v1/trust/{slug}A public trust page, resolved by slugadmin key · details
resolveTrustPageAdmin key only — the marketing host calls this on the reader's behalf. Private and absent slugs both 404 with the same body. The response never carries who edited the page. Cached for 30 s per slug; every PUT invalidates.
| Field | Type | Meaning |
|---|---|---|
slugrequiredpath | string | The public slug. |
| Field | Type | Meaning |
|---|---|---|
page | object | |
page.logId | string | |
page.slug | string | |
page.public | boolean | |
page.label | string | |
page.sections | string[] | |
stats | object | |
coverage | object | |
policies | object[] | |
halted | boolean | |
readiness | object |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Egress4 endpoints · browse
GET/v1/egressDestinations, deliveries and dead letters for one logtenant or admin key · details
egressOverviewEvery configured target (secrets never returned — hasSecret only), delivery stats, the dead-letter list, and the digest's state.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/egress/targetsAdd a webhook, Splunk HEC or Datadog destinationtenant or admin key · details
createEgressTargetHTTPS to a public host only (loopback, link-local, private, CGNAT, multicast, IPv4-mapped and NAT64 literals and bare hostnames are refused). Datadog v1 intake URLs (key in the path) are refused. The secret is shown once in the response and never again. Chained under the author.
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
kindrequired | "webhook" | "splunk" | "datadog" | |
namerequired | string | |
urlrequired | string | |
eventsrequired | string | string[] | Event types, or `*`. |
token | string | Splunk/Datadog token; ignored for webhooks. |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
target | object | |
secret | string | Shown once. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}PUT/v1/egress/digestTurn the email digest on or offtenant or admin key · details
setDigestDaily or weekly, to named recipients, via Resend's HTTP API. 501 when no mailer is configured on the plane (AUDITANT_RESEND_KEY + AUDITANT_MAIL_FROM).
| Field | Type | Meaning |
|---|---|---|
logrequired | string | |
cadencerequired | "off" | "daily" | "weekly" | |
recipients | string[] | |
authorrequired | string |
| Field | Type | Meaning |
|---|---|---|
digest | object |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}POST/v1/egress/digest/sendSend the digest nowtenant or admin key · details
sendDigestNowOne send, outside the schedule, to the configured recipients.
| Field | Type | Meaning |
|---|---|---|
logrequired | string |
| Field | Type | Meaning |
|---|---|---|
ok | boolean |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "policy decisions are not configured"
}Standards4 endpoints · browse
GET/v1/aiucThe AIUC-1 evidence packtenant or admin key · details
aiucPackEvery AIUC-1 control the chain can evidence, control id → chain-derived proof with sequence numbers, and an honest not-evidenced for the rest. Deterministic for a given log and moment; empty logs say so rather than citing events that do not exist.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/receipts/{receiptId}One per-action signed receipttenant or admin key · details
getReceiptThe receipt body verbatim as it was signed (RFC 8785 canonical form, ECDSA P-256 with the checkpoint key), its signature and key id, and the public keys — enough to verify offline.
| Field | Type | Meaning |
|---|---|---|
receiptIdrequiredpath | string | From a /v1/decide response. |
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
| Field | Type | Meaning |
|---|---|---|
receiptId | string | |
hash | string | |
keyId | string | |
signature | string | |
body | string | |
receipt | object | |
publicKeys | object[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "no route for GET /v1/nope"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/telemetryOCSF projection of decisions — a pull, not a streamtenant or admin key · details
telemetryDecisions and actions as OCSF API Activity (class 6003) with the dictionary's own disposition_id values (Allowed 1, Blocked 2, Delayed 14, Challenge 23, Other 99). Filter by action type, decision (including DEFER), agent and time. Paginate with limit.
| Field | Type | Meaning |
|---|---|---|
logrequiredquery | string | The log id, e.g. `tenant_acme/prod`. A tenant key may only name its own; anything else is a flat 403. |
actionTypequery | string | tool_call | model_call | decision … |
decisionquery | string | allow | deny | pending_approval | defer | modify |
agentquery | string | An actor id. |
fromquery | string | RFC 3339 lower bound. |
toquery | string | RFC 3339 upper bound. |
limitquery | integer | Max events. |
| Field | Type | Meaning |
|---|---|---|
events | object[] |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "ts must be RFC 3339 with an explicit offset (field: ts)"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}GET/v1/pricesThe versioned model price tabletenant or admin key · details
pricesWhich table was in force at a moment, and — with model — the per-1M-token prices that model resolves to, with the candidate names tried. No key needed for the table; prices are public numbers.
| Field | Type | Meaning |
|---|---|---|
atquery | string | RFC 3339 — which table was in force then (default now). |
modelquery | string | A model name as it arrives; resolved through the candidate list. |
| Field | Type | Meaning |
|---|---|---|
tables | object[] | |
price | object |
| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "unauthorized"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "forbidden"
}| Field | Type | Meaning |
|---|---|---|
errorrequired | string |
{
"error": "internal error"
}