REST APIAudit Events

Every meaningful action gets an audit event: hashed on receipt, Merkle-batched, and anchored on Solana. The lifecycle is visible on the record itself: received → batched → anchored.

What lands in an agent’s journal without you doing anything:

Event typeWritten by
control.decision, control.decision.completed, control.decision.receiptthe gate: every decision, its completion and the retained receipt
payment.authorized, payment.rejectedthe mandate ledger: each allow or refusal of POST …/mandates/<id>/authorize
mandate.created, mandate.version_createda mandate issued, and every change of its terms (commitment only, never the ceilings)
agent.revokedthe kill switch

Events you ingest yourself (below) sit next to them under the same agent.

Read an agent’s journal

GET /v1/organizations/<org>/agents/<agent_id>/events?limit=50&offset=0

Newest first. Each item carries event_type, status, payload_hash, batch_id and the Merkle fields once batched.

Ingest an event

curl -X POST https://api.regentprotocol.org/v1/organizations/<org>/audit/events \
  -H "Authorization: Bearer rgnt_..." -H "content-type: application/json" \
  -d '{
    "event_id": "action-<jti>",
    "agent_id": "agent_688b10bc62aef…",
    "event_type": "action.completed",
    "payload": {"amount": "25", "currency": "USD", "authorization_jti": "…"}
  }'
  • event_id — your idempotency key (≤64 chars). Re-sending the same id is safe.
  • event_type — dotted, e.g. action.completed, order.shipped.
  • payload — arbitrary JSON; it is hashed (payload_hash) and stored.

Best practice: put the decision id or the authorization jti into the payload — that is what ties the action to its permission when someone reconstructs the case later.

Read an event

GET /v1/organizations/<org>/events/<event_id>
{
  "event_id": "action-…",
  "agent_id": "agent_688b…",
  "event_type": "action.completed",
  "payload_hash": "…",
  "status": "anchored",
  "batch_id": "…",
  "merkle_index": 3,
  "merkle_proof": ["…"],
  "received_at": "…",
  "anchored_at": "…"
}

The event must belong to an agent of your organization; otherwise 404.

Verify a proof

POST /v1/organizations/<org>/events/<event_id>/verify
GET  /v1/organizations/<org>/audit/events/<event_id>/proof
GET  /v1/organizations/<org>/batches/<batch_id>

verify recomputes the event’s Merkle path against its batch root and answers verified: true|false. proof returns the same path together with the batch’s anchor so a reader can recompute it elsewhere. The batch record carries the on-chain commitment: anchor_tx (the Solana signature; anchor_chain: solana), solana_explorer_url, and the audit-chain position seq / chain_tx / chain_head with Regent’s signed checkpoint. The field arbitrum_tx_hash holds the same signature under its historical name and stays for older clients.

For a file a third party can check offline — the event, its proof, the checkpoint, the epoch and the keys — use the evidence bundle:

GET /v1/organizations/<org>/audit/events/<event_id>/bundle

An auditor can go further and check the anchor independently against Solana — the end-to-end recipe is in Verifying on-chain. That page is the point of the whole design: the trail is checkable without trusting Regent or the operator.

On devnet, batches seal and anchor within a minute of ingestion.

Verified on production: 2026-10-13.