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.

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 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. 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. 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