Resources
What our SMSC expects, and the two things that decide your actual throughput.
| Parameter | Value | Notes |
|---|---|---|
| Host | On request | Issued with your account. Bind only from addresses on your allowlist. |
| Port | 2775 | TLS available on request. |
| Bind type | Transceiver (TRX) | One session submits and receives. There is no transmitter/receiver split. |
| system_id | Issued per account | Maximum 15 characters — the SMPP v3.4 limit. |
| Interface version | 0x34 | SMPP v3.4. |
| Window size | 100 | A sensible default. Larger buys little; see below. |
| enquire_link | 30s | Required. A silent session is indistinguishable from a dead one without it. |
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.
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.
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_status | Meaning | Retry? |
|---|---|---|
| ESME_ROK · 0x00000000 | Accepted and queued. The message id in the response is what receipts will reference. | — |
| ESME_RTHROTTLED · 0x00000058 | Above your TPS. The session stays bound. | Yes — slow down first |
| ESME_RINVDSTADR · 0x0000000B | Destination is not a routable Indian mobile number. | No |
| ESME_RINVSRCADR · 0x0000000A | Sender ID is not registered to your account, not approved, or not re-confirmed with the operator recently. | No |
| ESME_RINVMSGLEN · 0x00000001 | Message body is empty, or longer than its encoding permits. | No |
| 0x00000401 · DLT-201 | No verified Principal Entity on the account. | No |
| 0x00000402 · DLT-202 | PE-TM chain is missing, pending, rejected or stale for this route. | No |
| 0x00000404 · DLT-204 | No approved template on your account is mapped to that sender ID. | No |
| 0x00000405 · DLT-205 | The wording does not match an approved template. Fixed text must be identical; only the variable parts may differ. | No |
| 0x00000406 · DLT-206 | Sender ID and template categories disagree. | No |
| 0x00000407 | Promotional traffic outside 09:00–21:00 IST. Not negotiable and not ours to waive. | Yes — after 09:00 IST |
| 0x00000408 | Prepaid balance below the cost of the message. | Yes — after topping up |
| 0x00000409 | Account suspended. | No |
| ESME_RSUBMITFAIL · 0x00000045 | Our 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.
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.
| PDU | Answer | Notes |
|---|---|---|
| bind_transceiver | Supported | TRX only. There is no transmitter/receiver split. |
| submit_sm | Supported | Validated on the call — see the status table above. |
| deliver_sm | Supported | Delivery receipts to you, on your own bound sessions. |
| enquire_link | Supported | Answered on any session. Send one every 30s when idle. |
| unbind | Supported | Acknowledged, then we close the socket. |
| query_sm | Supported | Returns the message_state and, once final, the date. Scoped to your account. |
| data_sm | ESME_RINVCMDID | Not supported. Use submit_sm — long messages are segmented for you. |
| submit_multi | ESME_RINVCMDID | Not supported. Submit one message per recipient. |
| cancel_sm | ESME_RCANCELFAIL | Nothing to cancel: a submit reaches the operator within milliseconds. |
| replace_sm | ESME_RREPLACEFAIL | Same reason. |
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.