Requesting a receipt, then reading it
An SMPP delivery receipt (DLR) is how your application learns whether a message actually reached a handset. It is the level-three confirmation that the three levels of error handling all build toward. First, you only get a DLR if you *asked* for one, via the registered_delivery field on the original submit_sm. Second, the SMPP delivery receipt format delivers the outcome in two places at once: a text blob and structured fields. Which one to trust depends on your SMPP version and provider.
registered_delivery: no request, no receipt
Why is registered_delivery required for SMPP delivery receipts?
Without setting registered_delivery in your SMPP submit_sm, the SMSC treats your message as fire-and-forget and never generates a delivery receipt. SMSRoute's API automatically handles this flag for you, ensuring every message gets a DLR without manual configuration.
Whether you get a delivery receipt depends entirely on the registered_delivery field you set when submitting the message. It is not automatic. A submit_sm without it asks for no confirmation, and you will never learn the outcome no matter how correctly your bind is set up. This is the second-most-common reason for 'my messages send but I get no DLRs' (after a transmitter-only bind).
- registered_delivery = 0 — no delivery receipt requested. You get nothing back.
- registered_delivery = 1 — request a receipt on final delivery (or failure). This is the usual setting.
- Other values — request receipts for intermediate states or on failure only, per the spec's bit flags.
- Set it per message — you control it on each submit_sm, so you can request DLRs for OTPs (where you care) and skip them for fire-and-forget bulk if you want.
The dual format: text blob and TLVs
How do SMPP delivery receipts come in dual format?
SMPP DLRs arrive as both a human-readable text blob (e.g., 'id:1234 sub:001 dlvrd:001') and structured TLVs (tag-length-value fields) for machine parsing. SMSRoute's API delivers both formats in every DLR webhook, so you can parse whichever suits your system best.
Here is the part that surprises people. To be compatible with both SMPP v3.4 and v5.0, the delivery status arrives *two ways in the same receipt*. The classic way is a text string in the short_message field with parseable stat and err components. The modern way is structured TLV (Tag-Length-Value) parameters: receipted_message_id, message_state, and network_error_code. The SMPP v3.4 specification defines the text format, while v5.0 introduced the TLV approach (SMPP v5.0 specification, 2026).
| Format | Where | Contains | Best for |
|---|---|---|---|
| Text (short_message) | The message body of the DLR | stat (status), err (error), id, timestamps | v3.4 compatibility; human-readable |
| TLV parameters | Optional TLV fields | message_state, network_error_code, receipted_message_id | v5.0; structured, less error-prone to parse |
The practical rule: prefer the TLVs (message_state, network_error_code) when your provider sends them. They are structured and unambiguous. Fall back to parsing the short_message te
Parsing it reliably
How can I parse SMPP delivery receipts reliably?
Parse the text blob using regex for fields like id, sub, dlvrd, and stat, or extract TLVs directly for precision. SMSRoute provides ready-to-use parsing examples in Python, PHP, Go, and Node on GitHub, eliminating guesswork and ensuring your integration works first time.
- Match the receipt to the original messageUse receipted_message_id (TLV) or the id in the text blob to correlate the DLR back to the message you sent. Store your submit_sm message ids so you can reconcile. This is the same discipline as REST-level DLR handling.
- Read message_state / stat for the outcomemessage_state (TLV) or stat (text) tells you DELIVERED, UNDELIVERABLE, EXPIRED, etc. This is the answer you requested the DLR for.
- Read network_error_code / err for the whyWhen a message failed, the error field explains it. This is a foundation for deciding whether to retry, revalidate the number, or try another channel.
- Handle both formats defensivelyTLVs first, text-blob fallback. Do not assume one. A provider or version change that drops you to the other format should not break your parser silently.
SMSRoute is a no-KYC SMS API with crypto billing (BTC, ETH, USDT, XMR, LTC, and SOL) and supports SMPP with delivery receipts alongside its REST API (where DLRs arrive as clean webhook callbacks instead of this dual binary format). If yo
Related reading
FAQ
What is the SMPP delivery receipt format?
Why am I not receiving SMPP delivery receipts?
What is the registered_delivery field in SMPP?
Should I parse the text blob or the TLVs in an SMPP DLR?
Send your first SMS in 5 minutes
How quickly can I send my first SMS with SMSRoute?
Sign up with just an email (no KYC), fund with crypto (BTC, ETH, USDT, XMR, LTC, SOL), get your API key, and send your first message—all in under 5 minutes. Free test credits are included to verify routes before you commit any real balance.
No KYC. Pay with BTC, ETH, USDT, XMR, LTC, and SOL. Live routes to 149 countries.
Get an API key →