Skip to main content

Webhook Event Payloads

This page documents the wire-level shape of an Orbit webhook delivery — the request envelope, the headers Orbit sends, and the metadata Orbit captures about every delivery attempt (including the request headers sent and the response headers received from your endpoint). For the full catalog of event types (message.delivered, call.completed, …) see Webhook Events. For HMAC signature verification see Webhook Security.

Request envelope

Every delivery is a single HTTP POST with a JSON body that follows the canonical envelope:
The data shape above is a successful delivery. Terminal-failure payloads (message.failed, which also covers the expired / submitted_no_receipt transitions) additionally carry optional error_code and error_message strings when the message has a provider-supplied failure reason — the raw code and text the carrier / channel returned. They are absent (not null) when no provider error was captured, and successful transitions clear them. See the webhook events reference for the full failure payload shape.

Request headers

Orbit sends every delivery with the following headers:

Inspecting delivery attempts

Orbit persists metadata about every delivery attempt (request headers sent, response status, response body, response headers received). Operators can inspect these via the dashboard or the API:
GET /api/v1/webhooks/{endpoint_id}/deliveries/{delivery_id}
Authentication: Clerk session or API key with webhooks:read scope. 200 OK

request_headers (captured since 2026-04, migration 217)

The exact header set Orbit sent on this delivery attempt. Useful for self-serve HMAC debugging — operators can inspect the X-Devotel-Signature value Orbit signed against and compare it to what their receiver computed. Redaction. Orbit redacts the value of any request header matching its secret denylist before persisting (the header name is preserved; only the value becomes <redacted>). Matching is case-insensitive. The full denylist is:
  • Authorization
  • Proxy-Authorization
  • Cookie
  • X-Api-Key
  • X-Auth-Token
  • X-CSRF-Token
  • X-Amz-Security-Token
  • Any header whose name matches X-*-Secret (starts with X-, ends with -Secret)
  • Any header whose name matches X-*-Token (starts with X-, ends with -Token)
  • Any header whose name matches X-*-Key (starts with X-, ends with -Key)
X-Devotel-Signature is deliberately not redacted — you need its plaintext HMAC digest to debug signature reconstruction. The redaction is one-way — once persisted, the original values are unrecoverable from the delivery row. This is intentional: the deliveries API is read-only and operator-facing; raw secrets must not surface in dashboard render paths even via inspect.

response_headers (captured since 2026-07-01)

The header set returned by your endpoint on this delivery attempt. Useful for:
  • Debugging your receiver’s CDN / WAF chain (e.g. confirming Cloudflare didn’t strip your body).
  • Correlating with your own logging — many receivers echo a request id (X-Request-Id / Traceparent) that the deliveries view can surface.
  • Validating that your receiver returned the expected Cache-Control: no-store for webhook responses.
Only headers your endpoint actually returned are captured, up to the first 100 header names (each value truncated to 1,024 characters). Set-Cookie is never persisted — a session cookie your server issues is a credential, so it is dropped before the delivery row is stored. Backwards compatibility. Deliveries recorded before 2026-07-01 (when Orbit began capturing response headers) carry response_headers: null. The dashboard renders a “headers not captured for this delivery” empty-state in that case — it does NOT block render of the delivery row itself.

last_response_body

Truncated to the first 500 bytes of the response body. Use for debugging your receiver’s error messages. No truncation marker is appended, so treat the value as potentially clipped whenever it reaches 500 bytes.

Listing recent deliveries

GET /api/v1/webhooks/{endpoint_id}/deliveries
Cursor-paginated. The same request_headers / response_headers fields are returned per row so the dashboard can render the headers panels inline without an extra round-trip per row. Query parameters

Replay + retry

If your endpoint was down or returned a non-2xx, Orbit retries on the delivery schedule. To force a replay of an already-completed delivery (e.g. after a downstream bug fix):
POST /api/v1/webhooks/{endpoint_id}/deliveries/{delivery_id}/replay
Creates a new delivery row with the same event_id and payload and queues it for immediate dispatch. The original row is preserved as audit trail. To re-queue a failed delivery (without changing the payload):
POST /api/v1/webhooks/{endpoint_id}/deliveries/{delivery_id}/retry
Resets the delivery’s status to pending and sets next_retry_at = now() so the worker picks it up on the next tick.

See also