Webhooks
Push Outpost events to your own systems via HTTP callbacks.
Webhooks forward Outpost events to downstream systems through HTTP callbacks. Instead of polling for message outcomes, your service registers an endpoint and Outpost pushes notifications - message delivered, message failed, phone opted out - as they happen.
In the dashboard: webhook configurations are managed per project, see Managing Tenants & Projects.
How they relate
Webhook configs live on projects - the same boundary that owns API keys and produced the traffic. Each config declares a destination URL (HTTPS only), optional auth (Bearer or Basic), custom headers, and an explicit list of subscribed event types.
What you can subscribe to
- Message events - the full lifecycle:
QUEUED,PROVIDER_ACCEPTED,DELIVERED,ATTEMPT_FAILED,FAILED,BLOCKED, and the rest.ATTEMPT_FAILEDfires when a delivery attempt fails but the message still has attempts remaining;FAILEDfires exactly once, when the message settles as failed for good. - Phone events - only
OPTED_OUTandOPTED_INare webhook-eligible. Because phones are global, an opt-out is delivered to every project that has messaged that phone (each project's configs are evaluated independently).
Subscriptions are explicit: a config with no subscriptions receives nothing.
The delivery request
Deliveries are POST requests with a versioned JSON payload containing the event fields plus fresh context - a message object (status, isSettled, cost, attempt count, your metadata bag) for message events, or a phone object (opt-out state, validation state, carrier) for phone events. isSettled lets you tell a terminal FAILED apart from an in-progress retry without re-deriving it from status alone.
Every delivery carries identifying headers, including:
| Header | Use |
|---|---|
x-outpost-event | The event type - route on this |
x-outpost-delivery-id | Unique per attempt - deduplicate on this |
x-outpost-project-id | Which project's config produced this |
x-outpost-payload-version | Payload contract version (currently 1) |
These header names are reserved and cannot be spoofed by custom header config.
Correlating with your own systems
Set metadata on your send request (items[].metadata) - Outpost never interprets it, but echoes it back inside the message context on every webhook delivery for that message.
Delivery semantics
- A 2xx response marks the delivery
SUCCEEDED; anything else marks itFAILEDwith the status code recorded. - Every attempt is persisted on the event record, so the dashboard can show exactly what was delivered where.
- Failed deliveries are not currently retried automatically - design your endpoint to be available, and treat webhook data as a notification layer over the authoritative API.
- A config can be paused without deleting it (
endpoint.isActive: false); paused configs are skipped at fan-out time.
Managing configs
Webhook configs are managed as project subresources: GET/POST /v1/projects/:projectId/webhook-configs and GET/PUT/PATCH/DELETE on /v1/projects/:projectId/webhook-configs/:webhookConfigId. The outbound payload shape is also documented in the OpenAPI document's webhooks section.
API reference
GET /v1/projects/:projectId/webhook-configs- list a project's configsPOST /v1/projects/:projectId/webhook-configs- add a configPATCH /v1/projects/:projectId/webhook-configs/:webhookConfigId- update (e.g. pause) a configDELETE /v1/projects/:projectId/webhook-configs/:webhookConfigId- remove a config- Outbound webhook payload - the exact shape Outpost POSTs to your endpoint
Calling from TypeScript? See Generating a Typed Client.