Once volume climbs past human-composed sends, one question arrives: REST — one POST per message, statuses back as webhooks — or SMPP, the binary session protocol SMS has run on for decades? On Orbit both doors are first-class and converge immediately after ingress — same sender resolution, same compliance gates, same routing. The choice is the wire, not the capability.
1. Quick decision tree
Work top-down; stop at the first decisive answer.
- Do you already operate SMPP client software? A gateway, an aggregator bridge, a platform off an SMSC. If yes, bind and skip the rewrite.
- Are messages arriving in bursts or steadily? Bursty → REST: concurrency is parallelism, no session to keep warm. Steady → SMPP: a persistent transceiver session amortizes TLS to zero.
- Which latency floor do you need? Both submit in milliseconds; the difference is receipts. SMPP
deliver_smarrives in-band on the session. REST statuses arrive as webhooks — one more network hop plus your listener. - How much machinery can you own? REST is a stateless POST plus a webhook endpoint. SMPP is a session you own:
enquire_link, reconnection with backoff, sequence bookkeeping, remote-window discipline.
For most new integrations the answer stops at 1 and 4 — there is no SMPP estate to reuse. For migrations off an SMSC and sustained high-MPS traffic, SMPP wins on 1 and 2 combined.
2. The SMPP path on Orbit
Create an SMPP credential under Developer → SMPP in the dashboard. You get a system_id and a password; the plaintext is returned once. Point your client at smpp.orbit.devotel.io:2775 with a bind_transceiver and submit_sm PDUs start flowing.
Bind-submitted traffic resolves the sender, runs the compliance gates, routes, and bills exactly as REST-submitted traffic; every PDU becomes a Messages row with its full status trail. Delivery receipts stream back in-band as deliver_sm per the credential's dlrMode. The SMPP Inbox toggle (off by default) keeps machine traffic out of the team Inbox; replies still thread normally. Session discipline — keepalives every 30–60 seconds, reconnect with backoff, respect the remote window — is the discipline any SMSC asks for. The operational playbook lives in SMPP bind management and the companion playbook post Running SMPP on Orbit. This post only answers when the bind is the right door.
3. The REST path on Orbit
One HTTPS POST per message to POST /api/v1/messages/sms — to, from, body, optional sender_pool_id. The send returns 202 Accepted with data.id (msg_ + 32 hex chars) and data.status: queued. The SMS channel doc walks the request shape end to end.
Three properties make this path hold up at volume:
- Idempotency built in. Send an
Idempotency-Keyheader; a retry presenting the same key returns the original envelope — no duplicate send, no second charge. The SDKs mint a UUID per call; over raw HTTP, pass one stable key across the retries of one logical send. - Delivery statuses as webhooks. Subscribe to
message.sent,message.delivered, andmessage.failedand each transition pushes the message id and new status to your listener. If you cannot run a listener, pollGET /messages/{id}. - Explicit failure semantics. Terminal rows carry a machine-readable
metadata.classified_error_code:rejectedis the pre-carrier gate (deterministic, do not retry);undelivered/failed/submitted_no_receiptare carrier-side outcomes (route through troubleshooting, never blind-retry).
The measurable ceilings: a 100 requests/minute per tenant default on POST /messages/sms (raise it on a plan change), plus sender-side caps — per-day, per-number on US 10DLC, route-dependent elsewhere. A sender pool spreads volume across registered senders when the sender side binds; it does not lift the API floor, which is what pushes sustained senders toward SMPP.
4. Worked example: the same campaign both ways
A 120,000-message OTP blast, steady-state, receipts required in a bounded window for cleanup.
Via REST. 120,000 POSTs. At the default 100 requests/minute per tenant floor, submission alone takes 1,200 minutes. Raise the limit to 5,000 req/min and it drops to 24 minutes — but you still carry per-message TLS, webhook hops, and idempotency-key bookkeeping.
Via SMPP. One persistent transceiver bind. Throughput is the negotiated window × pipelining depth; a healthy window sustains tens of messages per second, and binds multiply linearly. At a conservative 50 MPS per bind: submission lands at 40 minutes, receipts stream in-band as deliver_sm, and session health is one enquire_link cadence away. The platform cost is the one session and one credential.
Same destination, same compliance gates, same Messages rows, same billing. The difference is which per-message overhead your infrastructure already amortizes.
5. Migration hybrid: bind in front, REST behind
The realistic migration is the shape most high-volume movers end up running:
- Stand the SMPP bind up first and move peak/steady traffic — OTP, MFA, alerting — where the session pays for itself; in-band
deliver_smbuys the most there. - Keep the REST path as the fallback plane — one-off or bursty sends, emergency route when a bind rebuilds. The send semantics are identical, so application code needs one branch, not one integration, per door.
- Let statuses converge downstream. Both doors land Messages rows with the same lifecycle; what differs is ingress and the receipt channel — in-band
deliver_smon the bind, webhooks or polling on REST — so the hybrid is a per-route choice.
6. Trade-offs that actually differ
| Axis | REST + webhooks | SMPP bind |
|---|---|---|
| Idempotency | Idempotency-Key header; duplicate-safe retries return the original envelope | Duplicate submit_sm sequence handling per the SMPP spec; your client owns sequence bookkeeping |
| TLS | Per-request handshake, amortized only by your HTTP client's keep-alive | Session-scoped: established once at bind, amortized to zero per PDU |
| Throughput ceiling | 100 req/min default API floor (raise on plan) + sender-side caps | Negotiated window × pipelining; scales with bind count |
| Receipt path | Webhook delivery (subscriber-side listener, retries) or polling | In-band deliver_sm on the session |
| Coding effort | One POST + one webhook endpoint; a few lines in any language | An SMPP client stack: bind lifecycle, keepalives, sequence state, PDU encode/decode |
| Ops burden | Webhook endpoint availability; retry handling on 4xx/429 | Session liveness (enquire_link), reconnect with backoff, remote window discipline, credential rotation |
| What stays identical | Sender resolution, compliance gates, routing, billing, Messages lifecycle, tenant ownership of controls | Same |
The columns are not symmetric: SMPP's wins are throughput and receipts in-band; REST's wins are idempotency you do not build and coding/ops effort that stays in reach.
Frequently asked questions
Does SMPP open any capability REST lacks — features, routes, or receipts?
No. Both doors reach the same routing and receipts; SMPP is a wire choice, not a feature gate. The capability set — sender pools, compliance, lifecycle, billing — is identical.
Can I run SMPP and REST at the same time on one tenant?
Yes — that is the hybrid above. Traffic decides per message; records converge afterward. Most high-volume movers run exactly that while migrating traffic off REST onto the bind.
What happens when my SMPP bind drops mid-campaign?
The session teardrops too; a healthy client reconnects with backoff and resubmits sequence-safe PDUs. Nothing queues on the platform side for a dropped bind, so REST as the fallback plane (the hybrid) is the resilience pattern, not an either/or answer.
How do I pick a starting throughput target on the bind?
Start at the negotiated window your client keeps healthy at enquire_link every 30 seconds; add binds before you add window depth to one session. Sender-side caps (10DLC per-day per-number, route-dependent elsewhere) still bound the true ceiling — use a sender pool when the sender side is what binds.
The takeaway
SMPP vs REST on Orbit is a choice of wire, not capability: both doors reach the same routing, compliance, billing, and lifecycle. Pick REST when the integration is new, volume is bursty, and owning a session is the wrong trade. Pick SMPP when an SMPP client already exists or sustained throughput makes per-message TLS and webhook hops the costliest overhead you carry. Run the hybrid when migration is the move — bind in front, REST behind, one reporting surface underneath.
Published 25 September 2026.