Skip to main content

The MT termination model

Everything you send outbound — an SMS, a WhatsApp template, an MMS, a fax, a dialed call — is MT (mobile-terminated): traffic that ends on a handset or carrier network. The sibling pages each own one slice of that path: sender resolution names the sender, least-cost routing ranks the upstream route, unified termination routing decides the channel, and the queued-to-sent primer owns the status vocabulary. None of them answers the newcomer’s actual question: how does an outbound call or message physically leave Devotel Orbit and terminate? This page is that answer — the travel modes, the gates in order, the dispatch mechanics, the exit planes, the feedback loop, and the cost, all named once and then delegated to the owning page. Everything here is tenant-owned configuration: the flags, allowlists, carriers, and caps below are settings you carry, evaluated against your traffic only. The model is the same for every surface that generates outbound traffic — POST /api/v1/messages, campaigns, flows, journeys, the dialer, and the SMPP binds you connect.

1. Two travel modes — real-time session vs scheduled dispatch

Outbound termination travels in one of two shapes, and which one you are in decides almost everything downstream: The mode is chosen by which surface you call, not by a routing decision: the voice call endpoints open a session; the message endpoints enqueue a dispatch. Inside one mode, the second selection problem — which exit plane carries it — is shared, and the rest of this page treats both modes through the same gates, dispatch pipeline, planes, and feedback loop.

2. The pre-dispatch gate chain, in order

Before anything terminates, the send is admitted through a chain. Every gate reports a refusal with a documented code, in this order, and the first refusal ends the attempt:
  1. Request guards and admission — auth, rate limits, idempotency replay, and payload validation; API request guard pipeline owns the ordered table.
  2. Wallet pre-flight — an exhausted wallet refuses with 402 INSUFFICIENT_BALANCE; the billing gate chain owns the full chain, including the atomic check-and-decrement the send lands on afterward.
  3. Org outbound flags — a balance-driven SENDING_PAUSED (soft) or an account-lifecycle SENDING_BLOCKED (hard), both 402. Balance-driven pauses exempt the $0-on-platform free channels; account-lifecycle blocks exempt nothing. The pause gate and free-channel exemption owns the reason taxonomy.
  4. Country allowlist — a resolved destination country not on your opt-in list refuses with 422 COUNTRY_NOT_ALLOWED. This list is yours: with no list set, or an unresolvable destination, the send passes. Country allowlist gate owns the model.
  5. Recipient gates — quiet hours (recipient-local, your window), suppression and opt-out lists, duplicate-content claims, frequency caps, and throughput ceilings. Send gating and quiet hours owns the admission order and per-gate defaults. Voice to US recipients also carries the federal TCPA dialing-window guard, the one platform-owned gate with no tenant toggle; voice pre-send gate chain owns that order.
  6. Channel capability and template gates — the channel must support the payload (an MMS on an SMS-only sender, a WhatsApp template whose approval lapsed) and the sender must resolve. The channel capability matrix and sender resolution own those surfaces.
A refusal code tells you exactly how far the chain walked. A send that clears all gates proceeds to dispatch — never before.

3. Dispatch mechanics — enqueued vs direct, the worker fleet, retry budgets

Once admitted, dispatch takes one of two paths per async processing model:
  • Enqueued dispatch (the default). The API inserts the row (pending → queued) and returns 202; a worker in the webhook-worker staff claims it (sending), performs the provider handoff, and stamps the wire result. Scheduled send_at rows park as scheduled and join the same queue at fire time. Queue names and worker concurrency are declared in one central registry, so the health panel reads backlog and drain rate side by side; a persistent sending cluster means the provider endpoint is stalling, not the queue.
  • Direct (in-call) dispatch. A narrow set of immediate-response paths sends inside the request and answers synchronously, with a small bounded in-call retry budget. Only when every in-call attempt fails does the call site escalate the envelope to a durable retry queue with a long schedule (the email-retry and dlr-retry shapes), which a worker drains later.
Retries never re-bill: every movement riders on the idempotency key minted at admission, so a same-key retry collapses to the already-claimed ledger row and returns a 409 DEDUCT_IN_FLIGHT back-off rather than a second charge. The async processing model page owns the producer/consumer split and failure semantics; the scheduler fleet model owns the worker staff itself.

4. The terminal-routing planes — softswitch default, BYO by policy

Termination exits the platform on one of two planes, both tenant-controlled:
  • The Devotel wholesale softswitch (the default). Outbound voice and SMS terminate through Devotel’s wholesale softswitch trunk — SIP/RTP for calls, SMPP binds into the SMS leg. This is the only provider involved unless you bring your own; no outbound traffic is routed anywhere outside that boundary.
  • Your BYO carriers (opt-in). You connect an upstream carrier (an SMPP bind for SMS, a SIP trunk for voice), and your least-cost routing policy decides the order — rank BYO strictly by cost, by the composite quality score, or prefer-BYO-first — with the softswitch entry as the leaderboard to beat. The dry-run quote endpoint ranks routes for a destination without moving traffic, and route health and circuit breakers then meter whichever plane carries live traffic. The BYO carrier lifecycle page owns connection setup.
What “terminate” means per channel, and the failure code each leg reports: Whichever plane carries the send, the per-message provider column and the route-trace timeline (GET /api/v1/messages/:id/trace) answer “which leg did this take” in one call.

5. The status feedback loop — queued to terminal disposition

Dispatch is only half the loop; the other half is the receipt stream that closes it:
  1. Forward arcpending → queued → sending → sent, each transition fanning a message.* event to your webhook subscribers. sent on a receipt-capable channel is a submission acknowledgement, not a delivery claim.
  2. Terminal disposition — a carrier DLR resolves the row to delivered / read or to the failure codes above. On a no-DLR channel (Meta DM), sent is the provider’s best-ever answer and the row resolves to the submitted_no_receipt sentinel after its grace window; on a receipt-capable channel whose receipt never arrives, the row ages honestly to undelivered. Delivery lifecycle owns the per-status meanings; the queued-to-sent primer owns the whole vocabulary inline.
  3. Two DLR planes — carrier-plane receipts arrive through the provider into a status update; send-side receipts are encoded back out to you as webhook POSTs or SMPP deliver_sm. DLR model: two planes owns the split; the send-side DLR model owns the canonical six-state vocabulary your receiver merges against.
Voice sessions loop through the same vocabulary in call form: initiated → ringing → answered → completed with its dispositions, each event a webhook on the voice lane. Your integration never polls — the row is queryable GET /api/v1/messages/:id for repair reads, but the pipeline advances and reports itself.

6. Cost surfaces for MT

Termination spend resolves on four surfaces:
  • Per-channel rate cards — price per SMS segment, per WhatsApp conversation, per voice minute, per fax page. Pricing and rate resolution owns the attribution chain a destination’s per-unit price walks.
  • Wallet debit mechanics — the per-channel fund path of the billing gate chain: a voice hold of up to two minutes settled per-minute at hangup, per-segment SMS debits at send.
  • LCR interplay — the policy that trades the softswitch trunk against your BYO carriers; the dry-run quote shows an estimated unit price for the softswitch and honest null cents (unknowable upstream spend) for BYO rows.
  • Per-hop price bounds on cascadesmax_price rejects a pricey hop before billing and max_total_price trims a waterfall’s cumulative tail, per the notify cascade cost model.

7. A worked walk — one SMS end to end

POST /api/v1/messages with {"channel":"sms","to":"+14155552671","sender":"+14155550100","body":"Hi"} walks the whole model:
  1. Admission and gates — the guard pipeline accepts; the wallet pre-flight passes; org flags are clear; +1 is on your allowlist (or no list is set); no suppression entry and no quiet-hours block for the recipient; the sender resolves. Refusal codes along this span: 402 INSUFFICIENT_BALANCE / 402 SENDING_PAUSED|BLOCKED / 422 COUNTRY_NOT_ALLOWED / gate-specific 422s.
  2. Enqueue and dispatch — the row inserts as queued and the response returns 202 {"message_id":"msg_9f2"}; a send-queue worker claims it as sending.
  3. Termination — the LCR policy ranks the softswitch trunk against your BYO carriers; the winner’s SMPP bind takes the submit_sm; status goes sent. With unified termination rules enabled and an enforce match, the channel itself may switch before the plane ranks (see unified termination routing).
  4. Feedback — the carrier’s DLR lands: delivered, terminal. If 30 minutes pass with no receipt, the no-DLR sweep ages the row to undelivered; a genuinely late DELIVRD still flips it back under the transition DAG merge rules.
  5. Cost — one per-segment debit posts on the wallet under the message’s charge key, visible in usage records the same minute.

8. A worked walk — one voice call end to end

POST /api/v1/voice/calls (or a UCaaS extension dialing out to the PSTN) walks the second travel mode:
  1. Gates — the same chain in voice order: wallet pre-flight, outbound flags, country resolution, the federal dialing-window guard and your voice gates, per voice pre-send gate chain.
  2. Session open — instead of a queue row, the voice plane opens a SIP session over the softswitch and takes the up-to-two-minute wallet hold at dial; initiated hits your call webhooks.
  3. Termination — SIP signaling negotiates the PSTN leg, a BYO SIP trunk wins only if your policy ranks it first, and RTP media flows for the call’s life; the row walks ringing → answered → completed.
  4. Settlement — at hangup the settle debits the delta above the hold at the FX rate locked at hold; an unanswered call refunds the hold in full.
  5. Feedback — the call recording pipeline closes the artifact loop and the voice events close the status loop, same as messages, on your subscribed endpoints.

See also