# SMS statistics

> Pull aggregate, daily and per-country SMS statistics from the 23 Telecom API — delivery rates, costs, clicks and conversions, with period presets and custom date ranges.
> Source: https://docs.23telecom.co.uk/sms/statistics/

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

Three endpoints cover reporting: totals, time series and country breakdown.
All require the `sms.read` permission and accept the same period filters.

## Common parameters

| Parameter | Default | Description |
| --- | --- | --- |
| `period` | `7d` | `today`, `yesterday`, `7d`, `30d`, `this_month`, `last_month` |
| `from` / `to` | — | Custom range `YYYY-MM-DD`. Use only when `period` is omitted; the `to` day is included |
| `source` | `api` | `api`, `broadcasts`, `all` |
| `country` | — | ISO code filter: `US`, `GB`, … |
| `sender` | — | Filter by sender ID |
| `phone` | — | Search by phone number (substring) |
| `status` | — | `delivered`, `undelivered`, `pending`, `expired` |

## Aggregate statistics

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

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

```json title="200 OK"
{
  "status": true,
  "stats": {
    "total_sent": 1250,
    "sent": 1200,
    "delivered": 1150,
    "undelivered": 30,
    "pending": 15,
    "expired": 5,
    "not_billed": 50,
    "failed": 30,
    "click_count": 42,
    "unique_click_count": 38,
    "action_count": 12,
    "sent_rate": 96.00,
    "delivery_rate": 95.83,
    "total_cost": 10.63,
    "avg_cost_per_msg": 0.0085,
    "currency": "EUR"
  },
  "period": {"from": "2026-01-14", "to": "2026-02-13"}
}
```

How the numbers relate:

```
Sent      = Delivered + Undelivered + Pending + Expired
TotalSent = Sent + NotBilled
```

| Field | Description |
| --- | --- |
| `total_sent` | All messages attempted |
| `sent` | Accepted by carrier (`total_sent − not_billed`) |
| `delivered` | Delivered to handset (`DELIVRD`) |
| `undelivered` | Failed: `UNDELIV`, `REJECTD`, `DELETED`, `UNKNOWN` |
| `pending` | Still in transit |
| `expired` | Delivery timed out — counted separately from `undelivered` |
| `not_billed` | Always `0` for API traffic; for broadcasts: messages never submitted to carrier |
| `failed` | Alias of `undelivered` |
| `click_count` / `unique_click_count` | Link clicks (broadcast traffic) |
| `action_count` | Recorded conversions |
| `sent_rate` | `(sent / total_sent) × 100` |
| `delivery_rate` | `(delivered / sent) × 100` |
| `total_cost` / `avg_cost_per_msg` | Cost in account currency |

## Daily statistics

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

Day-by-day breakdown for charts, sorted by date **ascending**.

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

Extra parameters:

| Parameter | Description |
| --- | --- |
| `granularity` | `auto` switches to hourly buckets on a single-day range (dates become `2026-02-13T09:00`) |
| `countries` | Comma-separated ISO codes `US,GB,DE` — also flips sorting to descending |

```json title="200 OK (one day shown)"
{
  "status": true,
  "daily_stats": [
    {
      "date": "2026-02-13",
      "sent": 195,
      "delivered": 188,
      "undelivered": 4,
      "pending": 1,
      "expired": 2,
      "not_billed": 3,
      "failed": 4,
      "click_count": 12,
      "cost": 1.66,
      "currency": "EUR"
    }
  ],
  "period": {"from": "2026-02-07", "to": "2026-02-13"}
}
```

## Country statistics

`GET /api/v1/sms/stats/by-country` (permission: `sms.read`)

Grouped by destination country, sorted by `total_sent` descending.

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

```json title="200 OK (one country shown)"
{
  "status": true,
  "countries": [
    {
      "country": "United States",
      "country_code": "US",
      "country_flag": "🇺🇸",
      "total_sent": 520,
      "sent": 500,
      "delivered": 485,
      "undelivered": 10,
      "pending": 3,
      "expired": 2,
      "not_billed": 20,
      "failed": 10,
      "click_count": 25,
      "delivery_rate": 97.00,
      "cost": 4.25,
      "currency": "EUR"
    }
  ]
}
```