Skip to content

Check the delivery status of a sent message.

GET /api/v1/sms/status/:message_id · Permission: sms.read

Terminal window
curl https://restlink23telecom.com/api/v1/sms/status/api_42_1743667200123456789_a3f8b2c1d9e45f67 \
-H "X-API-Key: $API_KEY"
200 OK
{
"status": true,
"message": {
"message_id": "api_42_1743667200123456789_a3f8b2c1d9e45f67",
"telecom_message_id": "6946d0f5-040b-106e-42c7-49026f2b5bc1",
"recipient": "+14155551234",
"segments": 1,
"message": "Your verification code is 847291",
"sender_id": "MyApp",
"status": "DELIVRD",
"status_code": "000",
"cost": 0.0085,
"created_at": "2026-02-13T10:30:00Z",
"delivered_at": "2026-02-13T10:30:04Z",
"clicked": true,
"total_click_events": 2,
"human_click_events": 1,
"bot_click_events": 1,
"first_click_at": "2026-02-13T10:31:00Z",
"last_click_at": "2026-02-13T10:32:00Z",
"first_human_click_at": "2026-02-13T10:31:00Z",
"last_human_click_at": "2026-02-13T10:31:00Z"
}
}

Live IDs start with api_; sandbox (sk_test_) IDs start with test_ and are retained for 24 hours. 404 NOT_FOUND distinguishes an unknown/expired sandbox ID, a test_ ID queried with a live key (use its sk_test_ key), and a live ID not in this workspace. telecom_message_id, status_code, cost and delivered_at can be null. Sandbox responses add "sandbox": true and an empty telecom_message_id, with no click fields. A missing ID in a portal session returns 400 INVALID_ID; an unavailable sandbox returns 503 SANDBOX_UNAVAILABLE; a failed lookup returns 500 INTERNAL_ERROR.

Status Description Final?
pending Queued, waiting to send No
sent Submitted to carrier network No
ENROUTE Accepted by carrier, in transit No
ACCEPTD Accepted by carrier for delivery No
DELIVRD Delivered to recipient’s handset Yes
UNDELIV Delivery failed (invalid number, phone off) Yes
REJECTD Rejected by carrier (filtered, blacklisted) Yes
EXPIRED Delivery timed out Yes
DELETED Message deleted on the carrier network Yes
UNKNOWN Outcome unknown, including a send whose result was unclear (for example a timeout); a later delivery report can still replace it No
failed Rejected by the gateway before routing (usually no route available), or an internal queue failure. Never charged — the portal reports these as Not Billed. Yes

Raw carrier statuses (ENROUTE, ACCEPTD, DELETED) can appear verbatim — treat any status not in your known set as non-final and keep polling, except the clearly terminal ones above. See delivery statuses for typical status flows.

When filtering the message list by status, the accepted filter values are delivered, undelivered, expired, pending, not_billed, sent, clicked and converted (legacy aliases failed and unknown represent undelivered plus gateway-rejected failed). clicked selects messages with a human click; converted returns no direct-API messages. The other values map to groups of the raw statuses above.

If you poll instead of using webhooks:

  • Poll every 3–5 seconds, stop on any final status.
  • Give up after a few minutes and treat it as in flight — nothing finalizes an API message automatically; rely on webhooks.
  • Prefer webhooks for anything beyond low-volume testing: they remove polling load and deliver statuses the moment carriers report them.