Resources

SMPP connectivity

What our SMSC expects, and the two things that decide your actual throughput.

ParameterValueNotes
HostOn requestIssued with your account. Bind only from addresses on your allowlist.
Port2775TLS available on request.
Bind typeTransceiver (TRX)One session submits and receives. There is no transmitter/receiver split.
system_idIssued per accountMaximum 15 characters — the SMPP v3.4 limit.
Interface version0x34SMPP v3.4.
Window size100A sensible default. Larger buys little; see below.
enquire_link30sRequired. A silent session is indistinguishable from a dead one without it.

Connections do not multiply throughput

Your TPS is an account-wide budget, shared across every bind you hold. Opening a second connection does not double your rate — it halves each connection’s share of the same number. This surprises people often enough to be worth stating plainly, because the usual response to slow throughput is to open more sessions, and that makes nothing faster.

What more binds do buy is resilience and window depth: if one session drops, the others carry on, and more sessions means more messages can be in flight awaiting a response. If you want a higher rate, ask us to raise the number — it is a line in your account, not a function of how hard you connect.

Being throttled

A submit above your budget is answered ESME_RTHROTTLED and the session stays bound. We do not disconnect you for going too fast — disconnection causes reconnect storms, which is a worse problem than the one it solves.

Treat it as backpressure: slow down and retry, do not tear the session down and rebuild it. A throttled submit has not been accepted and has not been billed.

submit_sm_resp: why a message was refused

We validate on the submit, not afterwards. An unregistered sender ID, wording that does not match your approved template, a destination that is not an Indian mobile number — all of it is answered on the submit_sm_resp, so your application learns about it in the same call rather than from a receipt hours later. Nothing refused here is queued and nothing refused here is billed.

Where SMPP v3.4 has a status that means exactly the right thing, we use it — your library already understands those. DLT has no equivalent in a specification written fifteen years before it, so those refusals use 0x00000400–0x000004FF, the block v3.4 reserves for SMSC-specific errors. The numbers line up with the DLT-2xx codes our REST API returns, so the same refusal reads the same on both.

command_statusMeaningRetry?
ESME_ROK · 0x00000000Accepted and queued. The message id in the response is what receipts will reference.
ESME_RTHROTTLED · 0x00000058Above your TPS. The session stays bound.Yes — slow down first
ESME_RINVDSTADR · 0x0000000BDestination is not a routable Indian mobile number.No
ESME_RINVSRCADR · 0x0000000ASender ID is not registered to your account, not approved, or not re-confirmed with the operator recently.No
ESME_RINVMSGLEN · 0x00000001Message body is empty, or longer than its encoding permits.No
0x00000401 · DLT-201No verified Principal Entity on the account.No
0x00000402 · DLT-202PE-TM chain is missing, pending, rejected or stale for this route.No
0x00000404 · DLT-204No approved template on your account is mapped to that sender ID.No
0x00000405 · DLT-205The wording does not match an approved template. Fixed text must be identical; only the variable parts may differ.No
0x00000406 · DLT-206Sender ID and template categories disagree.No
0x00000407Promotional traffic outside 09:00–21:00 IST. Not negotiable and not ours to waive.Yes — after 09:00 IST
0x00000408Prepaid balance below the cost of the message.Yes — after topping up
0x00000409Account suspended.No
ESME_RSUBMITFAIL · 0x00000045Our fault — we could not reach a dependency. You did nothing wrong.Yes

Retry only what says retry

The three retryable statuses mean the fault is ours or transient. Everything else will fail identically however many times you send it — a sender ID that is not registered at 21:00 is not registered at 21:01 — and retrying costs you a window slot per attempt. This is also why we stopped answering ESME_RSUBMITFAIL to everything: it is a retryable status, so it told well-behaved clients to do exactly the wrong thing.

Which PDUs we answer

What we do not support is refused, not accepted and dropped. That distinction costs us nothing and saves you finding out weeks later that a class of your traffic went nowhere — so a data_sm comes back ESME_RINVCMDID rather than ESME_ROK.

PDUAnswerNotes
bind_transceiverSupportedTRX only. There is no transmitter/receiver split.
submit_smSupportedValidated on the call — see the status table above.
deliver_smSupportedDelivery receipts to you, on your own bound sessions.
enquire_linkSupportedAnswered on any session. Send one every 30s when idle.
unbindSupportedAcknowledged, then we close the socket.
query_smSupportedReturns the message_state and, once final, the date. Scoped to your account.
data_smESME_RINVCMDIDNot supported. Use submit_sm — long messages are segmented for you.
submit_multiESME_RINVCMDIDNot supported. Submit one message per recipient.
cancel_smESME_RCANCELFAILNothing to cancel: a submit reaches the operator within milliseconds.
replace_smESME_RREPLACEFAILSame reason.

Delivery receipts

Receipts return as deliver_sm on your own bound session, spread across your sessions if you hold more than one. If every session is gone we hold them, bounded, and deliver them when you come back — a disconnection costs you a delay, not your reports.

The queue is bounded on purpose. A merchant who stays disconnected long enough will lose the oldest receipts rather than have us consume memory indefinitely on their behalf, and the depth is a number on your account you can ask us to raise.

Before you go live

  • · Send us the source addresses you will bind from. An empty allowlist accepts any address, which is convenient and not what you want in production.
  • · Confirm your sender IDs and templates are registered — a submission that does not match a registered template is refused before it reaches an operator.
  • · Implement enquire_link. Without it, a half-open socket looks healthy to both sides until messages start disappearing.
  • · Make your receipt handling idempotent. Receipts can arrive more than once.