# Get message status

> Check SMS delivery status by message ID with GET /sms/status. Returns carrier DLR status, cost, segments and delivery timestamp. Examples in 8 languages.
> Source: https://docs.23telecom.co.uk/sms/status/

Instructions for LLMs: This is one page of the 23 Telecom messaging API docs
(SMS today; more channels planned). Base URL: https://restlink23telecom.com/api/v1,
auth via the X-API-Key header. Match errors on the error_code field, never on
description text. Full docs: https://docs.23telecom.co.uk/llms-full.txt · Schemas: https://docs.23telecom.co.uk/openapi.yaml

Check the delivery status of a sent message.

`GET /api/v1/sms/status/:message_id` (permission: `sms.read`)

## Request

```
GET https://restlink23telecom.com/api/v1/sms/status/api_42_1743667200123456789_a3f8b2c1d9e45f67
Header: X-API-Key: <your key>
```
*(The web page shows this example in cURL, Node.js, Python, PHP, Ruby, Java, Go and .NET.)*

  `api_{user_id}_{nanosecond_timestamp}_{16_char_hex}` — for example
  `api_42_1743667200123456789_a3f8b2c1d9e45f67`. You receive it in the
  [send response](/sms/send#response).

## Response

```json title="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"
  }
}
```

Returns `404 NOT_FOUND` if the message does not exist or belongs to another
account.

## Status values

| Status | Description | Final? |
| --- | --- | --- |
| `pending` | Queued, waiting to send | No |
| `sent` | Submitted to carrier network | 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 |
| `UNKNOWN` | Final status unknown | Yes |
| `failed` | Internal error (queue/config failure) | Yes |

See [delivery statuses](/reference/delivery-statuses) for typical status flows.

## Polling guidance

If you poll instead of using [webhooks](/webhooks/delivery):

- Poll every **3–5 seconds**, stop on any final status.
- Give up after **a few minutes** and treat the message as in-flight — some
  carriers report late; the hourly reconciliation will finalize stuck messages.
- Prefer webhooks for anything beyond low-volume testing: they remove polling
  load and deliver statuses the moment carriers report them.