# Deliverability

Source: https://jointextkit.com/docs/deliverability
Index: https://jointextkit.com/llms.txt

Every final outcome of an outbound message (delivered or failed) is counted by
day, by the recipient's carrier and country, by the number you sent from, by
message category, by platform customer, by [tag](/docs/messages#send-a-message),
and (for failures) by failure code. Read the
numbers from the API, or open [Console → Deliverability](/console/deliverability)
for trends, your worst carriers and numbers, and a breakdown of failure
reasons.

Test keys report sandbox traffic; live keys report live traffic. The console's
Analytics page shows live traffic only. Counts only: no message content is part
of this data.

## GET /v1/deliverability

```bash
curl "https://api.jointextkit.com/v1/deliverability?group_by=carrier&start_date=2026-09-01&end_date=2026-09-30" \
  -H "Authorization: Bearer ssms_sk_live_..."
```

| Parameter | Default | Notes |
| --- | --- | --- |
| `group_by` | `day` | `day`, `carrier`, `number`, `country`, `category`, `customer`, `error_code`, or `tag` |
| `start_date` | 6 days before `end_date` | `YYYY-MM-DD`, UTC, inclusive |
| `end_date` | today | `YYYY-MM-DD`, UTC, inclusive. Ranges are limited to 90 days. |

```json
{
  "object": "deliverability",
  "mode": "live",
  "start_date": "2026-09-01",
  "end_date": "2026-09-30",
  "group_by": "carrier",
  "totals": { "key": "total", "delivered": 9412, "failed": 88, "total": 9500, "delivery_rate": 0.9907,
              "failure_reasons": { "invalid_number": 51, "carrier_filtered": 37 } },
  "data": [
    { "key": "example_wireless", "delivered": 2100, "failed": 61, "total": 2161, "delivery_rate": 0.9718,
      "failure_reasons": { "carrier_filtered": 37, "invalid_number": 24 } }
  ]
}
```

`failure_reasons` counts failed messages by their [failure code](/docs/errors#delivery-failures).
`day` rows come back in date order; `carrier` and `number` rows worst
first. The carrier is known when the recipient has been looked up recently
(`GET /v1/lookup`); otherwise it is `unknown`. Numbers are keyed by their
10 digits. `country` is `US` or `CA` (toll-free counts as `US`);
`category` and `customer` are `none` for messages sent without one;
`error_code` rows are failed messages by our
[failure code](/docs/errors#delivery-failures), most frequent first. `tag`
has a row per tag you sent with, plus `_untagged`; a message with two tags
counts in both rows, so the rows can add up to more than the totals. These
five are counted from 2026-10-24 on. Needs the `messages:read` scope on a restricted key.

## Degradation alerts

Every 15 minutes we compare each account's last 2 hours with its previous 7
days, for all traffic, each carrier, and each sending number. When the
delivery rate falls sharply (at least 15 points and at least 20% below
normal, with at least 20 recent and 100 baseline outcomes, so a handful of
failures can't trigger it), we:

- show the alert at the top of the Deliverability page,
- send a `deliverability.degraded` [webhook event](/docs/webhooks),
- and alert our team.

```json
{
  "type": "deliverability.degraded",
  "data": {
    "alert_id": "dal_...",
    "dimension": "number",
    "key": "4155550132",
    "window_rate": 0.41,
    "baseline_rate": 0.97,
    "window_total": 230,
    "baseline_total": 18400,
    "window_hours": 2
  }
}
```

`dimension` is `account` (all traffic), `carrier`, or `number`. Each
series alerts at most once every 6 hours.
