Configure
PUT /user/webhook
string
required
Destination URL. Pass
"" to clear it — null is rejected with 422.string
Shared secret used to sign each payload. Omit to leave the stored secret unchanged.
object
A map of event name to boolean, e.g.
{"meeting.completed": true}. An array is rejected with 422. Omit to leave the stored selection unchanged; when no selection is stored, the default events fire.GET /user/webhook
Response
Events
The typed events are additive:
meeting.status_change still fires for the same transition.
Signature
Each delivery carriesContent-Type: application/json and, when a secret is set:
Verify by recomputing the HMAC over
"<X-Webhook-Timestamp>." + raw_body and comparing in constant
time. Reject timestamps outside your replay window.
Delivery history
GET /user/webhook/deliveries
Response
limit defaults to 100 and accepts 1–500; the ledger keeps the most recent 100
attempts per account, so it is a recent window rather than a permanent audit log.
outcome is one of delivered · queued · suppressed · blocked · failed. status_code is
what your endpoint answered, when it answered. A row carries the host only — never the
configured URL, never the secret.
Don’t have a key yet? Hosted: sign in at vexa.ai/signin with a Google
account and copy your key from your account page — free credit, no card
required. Self-hosted: make all prints a key when the stack comes up.
What is proven, and what is not
- Live delivery — proven. Owner-witnessed production walk, 2026-07-19: POSTs arrived at an
external
webhook.siteinbox from production IPs, one per walk event, matched one-for-one by meeting-api’s delivery-outcome log atcode=200. - Delivery History — broken. The user-facing history reads a store real deliveries were never written to, so it lists none of them (#841, open). Do not read an empty history as “nothing was delivered.”
- CI does not exercise the network leg. The module and eval tests drive the real
WebhookSinkagainst a fake in-memory receiver, so a regression in the transport itself would not be caught by tests — only by another live walk. - No settings UI — configuration is API-only (
PUT /user/webhook). - Exactly-once emission (#519) and outage-durable retry (#520) both closed as completed in July.