How routing picks a sender — and where a reply lands
Routing is two-sided. Outbound, Orbit resolves which sender a message goes out from. Inbound (MO — mobile-originated), tenant-level rules decide where a received message lands. This page covers the inbound rule model end to end and keeps the outbound side in compact form; the full outbound chain lives on Sender resolution.Which page is authoritative for what
- This page is authoritative on inbound. Tenant-level MO rule dispatch — match types, dispatch targets, priority and conflict resolution, and the default-inbox fall-through — is covered here in full. The tenant-ownership layer underneath it (which tenant a received message resolves to, before any rules run) is Inbound message resolution; the full target vocabulary, failure counters, and validation guarantees are on Inbound message routing.
- Sender resolution is authoritative on outbound. Its chain of six source types, all four pool strategies with fail-safes, the per-country
country_sender_poolsmap, channel-specific rules, and the fallback chain all live there. This page keeps only a compact index of that chain so it stays readable; when the two disagree, that page wins. Choosing between a pool, a service, and an inline sender in the first place is the decision model on Choosing a sender construct.
Outbound: pick a sender (summary)
OnPOST /api/v1/messages/sms, Orbit resolves the sender from the first source that produces one, in this order:
from_extension— a UCaaS extension identity; resolves to the DID assigned to that extension.sender_pool_id— a rotating pool; the pool’s strategy picks one member and overrides a barefromon the same body.from— pin the sender directly, honoured only when no pool id rode along.messaging_service_id— the service’s own sender source fills in when the body carries neither a pool nor an explicit sender.- Conversation sticky sender — two-way replies pin the sender to the DID the contact originally texted.
- Fallback chain — org default sender → your first active number → the platform default number for
+1destinations or theDevotelalphanumeric sender ID for international destinations.
Inbound: route a received message (MO)
Tenant-level inbound rules are evaluated in priority order (lower value first; ties break by creation time, oldest first) and match on:number— the destination DID the message arrived onsender— the originating addresskeyword— case-insensitive substring of the message bodyregex— a regular expression tested against the body
webhook (signed HTTPS POST), a queue, an inbox, a team, or an ivr keyword menu tree. Evaluation is first-match-wins: once a rule matches, later rules are never consulted, so ordering matters — put specific exceptions at lower priority values than broad catch-alls, and leave gaps (10, 20, 30) so you can insert a rule between two existing ones without renumbering.
When no rule matches, the message falls through to the default inbox and the message.received event, so rules are an overlay on your baseline handling, never a replacement for it. Manage rules under /api/v1/messages/inbound-routes; the full target vocabulary (auto_reply, appointment), failure counters, and validation guarantees are on Inbound message routing.
This tenant-level rule set sits above the per-DID inbound hooks you may also have configured: pools own the “which sender” decision, these rules own the “where the reply lands” decision.
Worked example — inbound MO keyword match into a queue
An inbound-routing tenant has an existing catch-all rule — keywordsupport into the support team at priority: 30 — and wants customer replies containing urgent to reach the on-call queue first. Create the specific rule at a lower priority value:
please call support — this is urgent arrives on your DID:
- Rules load in priority order. Rule “Urgent escalations to on-call queue” (
priority: 10) evaluates before the catch-all “support” rule (priority: 30) — lower value first. - The keyword matches.
urgentis a case-insensitive substring match, so the body containing “urgent” hits rule 1. - The message dispatches to the queue. The matched conversation is handed to
queue_oncallfor the on-call team — first-match-wins, so thepriority: 30catch-all is never consulted for this message. - If it had matched nothing. A message containing neither keyword — say
ok thanks— skips both rules and falls through to the default inbox, firing the tenant-widemessage.receivedevent exactly as if no rules existed.
See also
- Choosing a sender construct — the decision model: which of the outbound constructs to build, and which inbound layer owns a reply
- Sender resolution — the authoritative outbound chain: every strategy, per-country pools, channel rules, and the fallback chain in full
- Messaging services — the entity definition: what the bundle contains and when its defaults apply
- Least-cost routing (LCR) policy — the upstream-route ranking stage that runs after sender resolution
- Unified termination routing — the engine that decides whether the resolved sender actually delivers on SMS or terminates onto another channel, and its shadow→enforce lifecycle
- Inbound message routing — the inbound rule-engine reference: all target types, webhook signing and SSRF guards, SMS menus, failure tracking
- Inbound message resolution — the tenant-ownership layer underneath inbound routing (number index, reconcile, per-DID override)
- Sender pools guide — create pools, preview picks, read health
- Messaging credentials & services — attach a pool as a service’s sending identity
- Send and receive messages — end-to-end walkthrough