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 firesmessage.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:
- The
data.normalizedblock stamped on inbound message and opt-out envelopes - The
normalized.inboundshare event — one subscription covering the whole inbound family - The inbound-events catalog endpoint — the machine-readable mapping table of every upstream carrier status to the canonical event it resolves to
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:
*) 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-eventskind, and the full list of upstream carrier statuses (grouped by carrier — the Devotel softswitch, Telnyx, DIDWW, and Meta) that normalize to it.
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.
Quick-scan carrier-status matrix (snapshot)
Quick-scan carrier-status matrix (snapshot)
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.
"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
- Webhook Events catalog — every event type you can subscribe to
- Webhook Event Payloads — the full envelope and header anatomy
- Webhook Overview — endpoints, signing, retries, and the dead-letter queue
- Webhook Security — signature verification