SMS Delivery Reports (DLR) API — Real‑Time Message Status
Know exactly what happened to every message. Pull delivery status on demand, or have us push operator receipts to your webhook the moment they arrive — delivered, failed, expired or rejected — so your dashboards, retries and audit trails stay perfectly in sync.
Pull or push — your choice
Pull (polling)
Call the DLR endpoint with a broadcast ID or message ID whenever you want the latest status. Simplest to build — ideal for batch reconciliation and reports.
Push (webhook)
Register a callback URL once. We POST each delivery receipt to you in real time as the operator confirms it — no polling, instant retries and live dashboards.
Query delivery status
Pass your credentials and the broadcast_id returned by the send API (or a specific message_id) to get current status.
GET https://smsgatewayprovider.com/api/smsdlr?username=acme&apikey=YOUR_API_KEY&broadcast_id=1706donef4-2b9c-4d1a
| Parameter | Required | Description |
|---|---|---|
| username | Yes | Your account username / API login. |
| apikey | Yes | Your secret API key. |
| broadcast_id | Yes* | The broadcast ID returned when you sent the message(s). Returns status for the whole batch. |
| message_id | Yes* | Status for one specific message. *Provide either broadcast_id or message_id. |
| response | No | json (default) or text for a plain‑text status. |
Response
{
"broadcast_id": "1706donef4-2b9c-4d1a",
"reports": [
{
"message_id": "48386421654978667841",
"number": "919876543210",
"sender": "ACMEIN",
"status": "DELIVRD",
"submitted_at": "2026-08-14 13:50:02",
"delivered_at": "2026-08-14 13:50:18",
"parts": 1
}
]
}
Delivery webhook (callback)
Register a public HTTPS URL in your API settings (or send it as notifyUrl when submitting). We POST a receipt to it for every status change. Respond with HTTP 200 to acknowledge; we retry with backoff if you don't.
# We POST to your callback URL POST https://your-app.com/webhooks/sms-dlr Content-Type: application/json { "message_id": "48386421654978667841", "broadcast_id": "1706donef4-2b9c-4d1a", "number": "919876543210", "sender": "ACMEIN", "status": "DELIVRD", "submitted_at": "2026-08-14 13:50:02", "delivered_at": "2026-08-14 13:50:18" }
Security tip: verify the source IP or a shared secret/signature header before trusting a callback, and always return 200 quickly — queue any heavy processing so retries aren't triggered by slow responses.
DLR status codes
We normalise operator receipts to a consistent set of statuses. The raw operator value is kept alongside for auditing.
| Status | Final? | Meaning |
|---|---|---|
| DELIVRD | Yes | Delivered to the handset — confirmed by the operator. |
| SENT | No | Accepted and submitted to the operator (SMSC); awaiting the final receipt. |
| PENDING | No | Queued or in transit; a final status will follow. |
| UNDELIV | Yes | Undeliverable — handset unreachable, switched off or invalid. |
| FAILED | Yes | Operator rejected or the message could not be processed. |
| EXPIRED | Yes | Validity period elapsed before delivery could be confirmed. |
| REJECTD | Yes | Blocked — DND/NDNC, template mismatch, or blacklisted number. |
Final statuses will not change — safe to close the record. Non‑final statuses (SENT, PENDING) are interim; keep polling or wait for the push callback.
DLR API — frequently asked questions
Should I poll (pull) or use a webhook (push)?
How long does a delivery report take?
SENT or PENDING until the handset is reachable, up to the validity period, after which it becomes EXPIRED.Why is a message stuck at SENT?
SENT means the operator accepted it but hasn't returned a final receipt yet — usually the handset is off or out of coverage. It will resolve to DELIVRD, UNDELIV or EXPIRED. Treat only final statuses as conclusive.How do I match a report back to my message?
broadcast_id, and each recipient gets a message_id. Both appear in pull responses and push callbacks, so you can reconcile against your own records reliably.Do you keep delivery history?
How should my webhook respond?
200 as fast as possible to acknowledge receipt, then process asynchronously. If you return a non‑200 or time out, we retry with exponential backoff so no receipt is lost.



