Event objects — the same shape the SSE stream emits — at-least-once, signed, and retried. (Webhooks carry every event type — turn.completed, exec.completed, messages, … — not just messages.) Filter what you receive so you’re not spammed with internal chatter.
Destinations
level is the visibility threshold (user default, or progress); types is an optional event-type allow-list (default: all — which includes the terminal turn.completed); include_raw: false strips body.raw from the delivered Event. To get only completions, set types: ["turn.completed"].
| Method · Path | Purpose |
|---|---|
POST /sessions/:id/destinations | Register a destination. |
GET /sessions/:id/destinations · GET …/:did | List / fetch. |
PATCH /sessions/:id/destinations/:did | Pause or resume (enabled), retune level/types, or rotate secret. |
DELETE /sessions/:id/destinations/:did | Remove. |
webhook in POST /v3/sessions so it’s registered before the agent produces output. (Replaying earlier events with backfill_from_seq is coming soon.)
Deliveries
Every send and its outcome — the data behind a deliveries dashboard.| Method · Path | Purpose |
|---|---|
GET /sessions/:id/deliveries?destination=&status= | List deliveries — status, attempts, last response/error. |
GET /sessions/:id/deliveries/:id | One delivery, in detail. |
POST /sessions/:id/deliveries/:id/redeliver | Re-send — any delivery, not just dead-lettered. |
pending → delivering → delivered, or failed (retrying) → dead_letter after the max attempts.
Coming soon: full request/response body capture in delivery detail (today records status, attempts, response code, and error); a test-ping for a destination; and org/agent-scoped destinations that persist across sessions.
Delivery contract
- HTTPS only. Private, loopback, link-local, and cloud-metadata addresses are refused.
- At-least-once. Retried with exponential backoff; after the max attempts a delivery is dead-lettered (inspect and redeliver it above). A duplicate can still arrive — a send that succeeds as the worker dies, or a replayed turn — so dedupe on
webhook-id(it equals the event id). - Signed with Standard Webhooks. Every request carries
webhook-id,webhook-timestamp, andwebhook-signature— so you can verify with an off-the-shelf library instead of hand-rolling.webhook-signature=v1,<base64(HMAC-SHA256(secret, "{webhook-id}.{webhook-timestamp}.{rawBody}"))>. Verify against the raw request body, before parsing it;webhook-timestampguards replay; yoursecret(whsec_…) is write-only — set once, never returned. PlusX-OC-Delivery-IDandX-OC-Session-IDfor correlation. - A delivery succeeds on HTTP
2xx.
Verify a webhook
Use a Standard Webhooks library:Today, delivery is over generic webhooks. Slack, GitHub comments, Jira, and email are coming soon — all on this same envelope and delivery contract.