Skip to content
VestiarionDocs

Webhooks

Payload and headers

The body and headers of every webhook delivery.

Every delivery is a POST with Content-Type: application/json, the headers below, and a JSON body.

Headers

HeaderValue
User-AgentVestiarion-Webhooks/1
Vestiarion-Event-IdThe delivery's id (a UUID): the same on every retry of the same delivery.
Vestiarion-Event-Typeledger.appended or webhook.test.
Vestiarion-Signaturet=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>. See Verifying the signature.

Body

The body is one JSON object:

json
{
  "id": "3fa1e2b0-...",
  "type": "ledger.appended",
  "createdAt": "2026-09-29T11:55:00.370366+00:00",
  "workspace": { "slug": "acme" },
  "entry": {
    "seq": 82,
    "ts": "2026-09-29T11:55:00.370366+00:00",
    "actor": "agent",
    "domain": "treasury",
    "action": "sweep_to_usyc",
    "summary": "Treasury: sweep_to_usyc 60.71 USDC",
    "detail": { "decision": { "action": "sweep_to_usyc", "amount": 60.71 }, "executed": true },
    "bodyHash": "8780d07cb3d0...",
    "prevHash": "0000...0000",
    "hash": "b0ac72908868...",
    "signature": "c14f06b7...",
    "signingKeyId": "97a8a48af020f908"
  }
}
FieldMeaning
idThe delivery's id, the same as the Vestiarion-Event-Id header. De-duplicate on it.
typeledger.appended or webhook.test, the same as the Vestiarion-Event-Type header.
createdAtFor ledger.appended, the entry's time; for webhook.test, the time the test was queued.
workspace.slugThe workspace the event belongs to.
entryThe ledger entry. ledger.appended only.

entry carries the same fields as GET /api/v1/ledger reports for that row, without the row id, so a receiver already reading that API recognizes the shape. signingKeyId is null on entries written before key ids were recorded.

A webhook.test delivery has no entry at all: only id, type, createdAt (the queued time) and workspace.

Your response

Answer with any 2xx status, within 10 seconds. Vestiarion reads at most 1 KB of your response body and does not otherwise inspect the body or the headers. Any other status, a timeout or a redirect is a failed attempt: see Retries and disabling.