Skip to main content

Normalized inbound event envelope

Inbound messaging events (received messages, delivery receipts, failures, reads, opt-outs) come from several upstream carriers, and each carrier reports a different status vocabulary: Telnyx fires message.sending_failed, SMPP receipts carry codes like UNDLV and DELIVRD, DIDWW reports its own status strings. Orbit folds all of them onto the same canonical webhook events — this page documents the three pieces that make that folding predictable:
  1. The data.normalized block stamped on inbound message and opt-out envelopes
  2. The normalized.inbound share event — one subscription covering the whole inbound family
  3. The inbound-events catalog endpoint — the machine-readable mapping table of every upstream carrier status to the canonical event it resolves to
Your existing subscriptions and signature verification are unchanged. All three are additive: receivers that ignore them behave exactly as before.

The data.normalized block

Deliveries whose event belongs to the inbound family carry an extra normalized object inside data:
The kind discriminator: The block is additive — every field your handler already reads keeps its existing name and position. Events outside the inbound family do not carry normalized. normalized is opt-in per endpoint. Add normalized.inbound to that endpoint’s event list (or subscribe to one of the individual inbound event names); matching an inbound family event is what enables the block. It is not added to every endpoint automatically. If you upgrade an existing endpoint, only deliveries sent after the subscription change include normalized; previously delivered events are not rewritten or replayed with it.

Subscribe once with normalized.inbound

normalized.inbound is a share-able subscription name that covers the whole inbound family at once. Set it as an endpoint’s entire event list and the endpoint receives message.received, message.delivered, message.failed, message.read, and contact.opted_out — without enumerating them:
Endpoints that subscribe to the individual event names (or to *) behave exactly as before — the share name is a convenience, not a replacement. The share subscription is supported by webhook API v1. You can combine normalized.inbound with individual event names in the same list; the share name is not required to replace the list, but duplicate deliveries are still avoided.

The inbound-events catalog

The mapping table itself is served by one authed endpoint:
GET /api/v1/webhooks/inbound-events
The response lists one entry per canonical event a receiver can observe. Each entry carries the canonical status, the high-level kind, and the full list of upstream carrier statuses (grouped by carrier — the Devotel softswitch, Telnyx, DIDWW, and Meta) that normalize to it.
The kind values here (delivery, failure, opt_out, received) describe the carrier-status mapping; the kind values on the data.normalized envelope block above (inbound, message, opt_out) describe the delivery’s place in the inbound family. Both are closed enums you can branch on.
This compact snapshot mirrors the carrier rows returned by the catalog, so you can check coverage offline. The live endpoint is the source of truth; fetch it before treating a new status as supported.
Use the catalog to check that your handler’s switch statement covers the same mapping the platform normalizes with — for example when adding support for a new carrier, or when a raw status appears in your logs that your switch does not yet handle. For the full error-signature coverage question and event semantics, see the Webhook Events reference. The response is versioned ("version": "v1"); versioning lets the platform add or revise mappings without silently changing the contract your receiver has pinned. The same table ships in the SDK as normalizeInboundEvent in the shared webhook normalization module: pass it a raw carrier status (with or without the carrier name) and it returns the canonical event and status pair, so receiver-side validation never drifts from the platform’s mapping.

See also