# List messages

> Query SMS message history with GET /sms/messages — pagination, status and country filters, unified API + campaign view, and streaming CSV export up to 1M rows.
> Source: https://docs.23telecom.co.uk/sms/messages/

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

Paginated list of sent messages with filtering.

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

## Request

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

| Parameter | Default | Description |
| --- | --- | --- |
| `page` | 1 | Page number |
| `limit` | 25 | Results per page (max 100) |
| `status` | — | `delivered`, `undelivered`, `expired`, `pending`, `sent`, `failed`, `unknown` |
| `phone` | — | Search by phone number (substring) |
| `country` | — | ISO code: `US`, `GB`, … |
| `sender` | — | Filter by sender ID |
| `period` | `7d` | `today`, `yesterday`, `7d`, `30d`, `this_month`, `last_month` |
| `from` / `to` | — | Custom range `YYYY-MM-DD` (omit `period`; the `to` day is included) |

## Response

```json title="200 OK"
{
  "messages": [
    {
      "id": 1847,
      "client_message_id": "api_42_1743667200123456789_a3f8b2c1d9e45f67",
      "recipient": "+14155551234",
      "sender_id": "MyApp",
      "message": "Your verification code is 847291",
      "status": "DELIVRD",
      "status_code": "000",
      "segments": 1,
      "cost": 0.0085,
      "created_at": "2026-02-13T10:30:00Z",
      "delivered_at": "2026-02-13T10:30:04Z"
    }
  ],
  "total": 1250,
  "page": 1,
  "limit": 10,
  "total_pages": 125
}
```

### Status filter mapping

| Filter | Matches statuses |
| --- | --- |
| `delivered` | `DELIVRD` |
| `undelivered` | `UNDELIV`, `REJECTD`, `DELETED` |
| `expired` | `EXPIRED` |
| `pending` | `pending`, `sent`, `ENROUTE`, `ACCEPTD` |
| `sent` | Same as `pending` (alias) |
| `failed` | Same as `undelivered` (alias) |
| `unknown` | `UNKNOWN` |

## Unified messages

`GET /api/v1/sms/messages/unified` (permission: `sms.read`)

Combines **API traffic and broadcast campaigns** in one view. Accepts the same
parameters as `/sms/messages` plus:

| Parameter | Default | Description |
| --- | --- | --- |
| `source` | `all` | `api`, `broadcasts`, `all` |

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

  The unified response is **not** the same shape as `/sms/messages`:
  `sent_at` replaces `created_at`, `source` is `"api"` or `"campaign"`, and
  click/conversion fields (`clicked`, `clicked_at`, `action_type`,
  `action_at`, `broadcast_id`, `broadcast_name`) are included.

```json title="200 OK (unified, one item)"
{
  "messages": [
    {
      "id": "3201",
      "source": "campaign",
      "recipient": "+447911123456",
      "sender_id": "Promo",
      "message": "50% off today!",
      "status": "DELIVRD",
      "status_code": "000",
      "cost": 0.042,
      "sent_at": "2026-02-13T09:00:00Z",
      "delivered_at": "2026-02-13T09:00:03Z",
      "clicked": true,
      "clicked_at": "2026-02-13T09:05:12Z",
      "action_type": "registration",
      "action_at": "2026-02-13T10:00:00Z",
      "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "client_message_id": null,
      "segments": 1,
      "broadcast_id": 42,
      "broadcast_name": "February Promo"
    }
  ],
  "total": 5420,
  "page": 1,
  "limit": 20,
  "total_pages": 271
}
```

## CSV export

`GET /api/v1/sms/messages/unified/export` (permission: `sms.read`)

Streaming CSV export with the same filters as the unified list:

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

What to expect:

- **Excel-compatible** — the body starts with a UTF-8 BOM.
- **Row cap** — default 1,000,000 rows; the active cap is advertised in the
  `X-Export-Limit` response header. Larger result sets are truncated silently,
  so narrow the date window to drill down.
- `Content-Disposition: attachment; filename="messages_export_<timestamp>.csv"`.