# Channel readiness

The same readiness report narrowed to SMS or RCS: the channel's own setup steps, the countries a sender still ought to be registered for, and the countries it can actually send to right now.

**Language:** en
**Audience:** developer
**TLDR:** GET /v1/project/{project}/readiness/channel/{sms|rcs} returns steps (add-sender / add-agent, register-country, first send), one warning (recommended-registrations — countries a sender should be registered for and is not, only once the channel has an active sender) and reach: the countries you can send to now, with a per-sender breakdown, senderCount and defaultSender. On this scope operational also requires a non-empty reach: clearing every blocker is not the same as being able to deliver. What a carrier or regulator DID to a registration — pending-review, rejected-registration — is not here: it moved to GET /project/{project}/attention on 2026-09-05. A country's own paperwork is a separate list on separate endpoints (GET /project/{project}/channel/registration-progress, then the per-country checklist), never mixed into these steps.
**Search keywords:** channel readiness, sms readiness, rcs readiness, which countries can I send to, reachable countries, coverage, sender registration, register a country, recommended registrations, warnings, add sender, add agent, default sender, senderCount, regulation, can I send to Spain, no coverage, operational, where did pending-review go, where did rejected-registration go, what does a country require, registration checklist, registration progress, registration paperwork, which countries have steps pending
**Related pages:** /platform-api/product-api/project-setup/readiness, /platform-api/product-api/project-setup/attention, /platform/en/channels/countries
**Docs index (every page):** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt
**This zone's index:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform-api/product-api/llms-full.txt
**This page:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform-api/product-api/project-setup/channel-readiness/ (HTML) · https://staging-instasent-docs-nextjs.oscar-284.workers.dev/platform-api/product-api/project-setup/channel-readiness.md (Markdown)

The [project report](/platform-api/product-api/project-setup/readiness) answers "is this project set up". This one answers the two questions you actually ask before sending on a channel: **what is still missing here**, and **who can I reach right now**.

It returns the same object, with `scope: "channel"`, and fills in the two fields the project scope always leaves empty: `warnings` and `reach`.

What it does **not** answer is what a carrier or a regulator did to a registration you already submitted. That moved out on 2026-09-05 — see [What moved to the attention endpoint](#what-moved-to-the-attention-endpoint).

[`GET /v1/project/{project}/readiness/channel/{channel}` - Setup steps, the recommended-registrations warning and real send reach for one channel.](/platform-api/product-api/reference)

`channel` is `sms` or `rcs`. Any other value returns `404` — it is a route constraint, not a validation error, so don't expect a field-level message back.

```bash
curl "https://api.instasent.com/v1/project/$INSTASENT_PROJECT/readiness/channel/sms" \
  -H "Authorization: Bearer $INSTASENT_TOKEN"
```

```json
{
  "entity": {
    "scope": "channel",
    "projectType": "standard",
    "channel": "sms",
    "percent": 50,
    "operational": true,
    "steps": [
      { "key": "add-sender", "completed": true, "isBlocker": true, "disabled": false, "skipped": false, "skippable": true },
      { "key": "send-first-sms-campaign", "completed": false, "isBlocker": false, "disabled": false, "skipped": false, "skippable": true }
    ],
    "warnings": [
      {
        "key": "recommended-registrations",
        "severity": "error",
        "count": 2,
        "rows": [
          { "channel": "sms", "senderId": "5f3a9b2c4d1e0f00112233ab", "senderName": "MYBRAND", "country": "ES", "source": "regulation", "urgency": "urgent", "audienceCount": null, "audienceShare": null, "reason": null },
          { "channel": "sms", "senderId": "5f3a9b2c4d1e0f00112233ab", "senderName": "MYBRAND", "country": "FR", "source": "audience", "urgency": null, "audienceCount": 412, "audienceShare": 0.0824, "reason": null }
        ]
      }
    ],
    "reach": {
      "reachableCountries": ["PT"],
      "senders": { "MYBRAND": ["PT"] },
      "senderCount": 1,
      "defaultSender": "MYBRAND"
    },
    "computedAt": "2026-09-04T16:20:31Z"
  }
}
```

## Steps

Same [step object](/platform-api/product-api/project-setup/readiness#a-step) as the project report — stable `key`, no copy — with a set that depends on the channel and the project type:

| `projectType` | `channel` | Steps, in order                                            |
| ------------- | --------- | ---------------------------------------------------------- |
| `standard`    | `sms`     | `add-sender`, `send-first-sms-campaign`                    |
| `standard`    | `rcs`     | `add-agent`, `register-country`, `send-first-rcs-campaign` |
| `api_sms`     | `sms`     | `add-sender`, `send-sms-recent`                            |
| `api_sms`     | `rcs`     | `add-agent`, `register-countries`, `send-rcs-recent`       |

`api_sms` is the wire value for what the customer knows as an **A2P Messaging project** — the one that sends through the [A2P Messaging API](/a2p-messaging-api/overview). Never show the raw value in a screen someone reads: it is the one field on this endpoint whose value has a customer-facing name that doesn't look like it.

The first step of each list is the blocker; the rest are `disabled` until it is done. `register-country` / `register-countries` completes as soon as one RCS registration has been submitted — submitted, not approved, because approval is the carrier's and the regulator's timeline, not a step the customer can complete. The `*-recent` steps look at the last 30 days, so they re-open on a quiet integration.

**SMS has no per-country step.** Registration exists on SMS too, but it is not something the customer starts by hand, so it never becomes a checklist item. What it does produce is the warning below.

## Warnings

Steps are what the customer can complete. **A warning is what the customer should act on but cannot tick off** — a country a sender ought to be registered for and is not. It appears only once the channel has an active sender: before that there is nothing to recommend registering.

One key:

| `key`                       | `severity` | What it means                                                                                                                 |
| --------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `recommended-registrations` | `error`    | Countries a sender **should** be registered for and is not. `count` is the total and may exceed `rows`, which is capped at 8. |

> **Warning**: **Not to be confused with `/project/{project}/recommendations`.** Three things in this API share the word and only this one is about coverage: `recommended-registrations` is a country a sender ought to be registered for and is not. The [recommendations endpoint](/platform-api/product-api/project-setup/recommendations) carries items of `type: "recommendation"` — next steps worth taking in a project that already works — and never mentions registrations. The MCP server's channel-readiness tool exposes this same warning under a field called `recommendations`, which is this one, not that endpoint.

`warnings` stays an array discriminated by `key` even with a single member, so narrowing on the key is still the right thing to write: the next warning to arrive inherits that shape instead of adding nullable fields to this one.

Every warning carries `key`, `severity`, `count` and `rows`. **`rows` is discriminated by the parent's `key`, never by which fields came back null.**

Rows of `recommended-registrations` describe a registration that does **not** exist, so they carry no status. Instead they say why the country is recommended:

- `channel` — `string`
  `sms` or `rcs`.
- `senderId` — `string`
  The sender the recommendation is for.
- `senderName` — `string`
  Its alias — the SMS `from`, or the RCS agent name.
- `country` — `string`
  ISO 3166-1 alpha-2.
- `source` — `string`
  `regulation` — a regulator requires it; `audience` — you hold contacts there; `org` — it is the organization's own country.
- `urgency` — `string | null`
  `urgent`, `upcoming` or `far`. How close the regulator's deadline is; `null` unless `source` is `regulation`.
- `audienceCount` — `integer | null`
  Reachable contacts in that country; `null` unless `source` is `audience`.
- `audienceShare` — `number | null`
  That country's `audienceCount` over the project's contacts with a mobile phone, between 0 and 1 and unrounded: round it yourself for display. It is the same base the audience threshold is measured against, since a country is recommended for its audience only when it holds at least 1% of those contacts and at least 25 of them. `null` unless `source` is `audience`.
- `reason` — `string | null`
  `sender-substituted` when that sender can already reach the country, but only with a different sender shown to the recipient. The recommendation stays, and stays urgent: that delivery is a temporary last resort, and registering is what fixes it. `null` otherwise.

A country already covered by a non-archived registration on that sender never appears here, whatever its status.

> **Note**: `audience` rows are left out only when the audience's country distribution is unavailable: the project has no audience, or the distribution could not be obtained at that moment. The distribution is refreshed at most every six hours, so contacts from a recent import can take up to that long to show here. `regulation` and `org` rows are always there when they apply, so a missing audience contribution is silent, never an error.

### What moved to the attention endpoint

Until 2026-09-05 this array carried two more keys, and if you integrated before that date they are what you are missing:

| Old warning key         | Where it lives now                                                                                |
| ----------------------- | ------------------------------------------------------------------------------------------------- |
| `pending-review`        | [`GET /project/{project}/attention`](/platform-api/product-api/project-setup/attention), same key |
| `rejected-registration` | [`GET /project/{project}/attention`](/platform-api/product-api/project-setup/attention), same key |

The key names survived the move, so the switch you already wrote still matches; what changed is the endpoint it reads from and the shape around it — an attention item is **one occurrence** with `entities` and `data`, not a warning with `rows`.

The reason is the boundary the two engines are built on: **readiness answers what is left to configure, attention answers what has broken.** A registration a carrier is still reviewing, or one a regulator turned down, is something that happened to a registration the customer already submitted — an event, not a configuration gap. `recommended-registrations` stayed because it is the opposite: a registration that does not exist yet.

> **Warning**: One consequence worth designing for: a rejected registration appears in **both** reports at once, on purpose. Attention reports the rejection as news, with its cause, for 30 days; readiness lists the country under `recommended-registrations` because a rejected registration is not coverage. They are not duplicates — they say different things and both are true. Render them where each belongs rather than de-duplicating them.

## Reach

`reach` is the positive counterpart of the warnings: **the countries this channel can send to right now.**

- `reachableCountries` — `string[]`
  The union across the channel's active senders, ISO 3166-1 alpha-2, deduplicated and sorted.
- `senders` — `object`
  Per-sender breakdown, keyed by alias. A sender that reaches no country is omitted, so this map can be shorter than the sender list — and it may arrive as `[]` rather than `{}` when it is empty. Normalise both to an empty map before you index it.
- `senderCount` — `integer`
  How many **active** senders the channel has, including those that reach nothing. This is not the size of `senders`, and the gap is the interesting part: an RCS agent with no accepted registration counts here and is absent there.
- `defaultSender` — `string | null`
  The project's default sender, when it is one of the active ones. It matters because a send that names no sender uses it — so the union above can promise more than a single send would actually reach. Always `null` on `api_sms` (A2P Messaging) projects, where nothing picks a default.

Reach is registration-aware, but not every pending register costs you a country. A country drops out when a registration is required and missing, when the register is waiting on the **regulator** axis (not yet classified, or filed and awaiting a decision), or when it is rejected or revoked. A register still being processed by the **operators** does not drop it: on SMS the country stays reachable while that runs. Reach is not a delivery gate: a country that drops out of reach can still receive messages — they go out, they are billed, and delivery is best-effort, so the operator may replace the sender or filter the message. What reach tells you is where the sender is cleared to arrive as itself. The two channels start from opposite defaults, which is why the same project can look very different on each:

- **SMS** allows by default over the operator catalogue — the same set as the sender's `acceptedCountries` — and subtracts what regulation blocks.
- **RCS** is registration-driven, so it can be **stricter** than the agent's `acceptedCountries`, which reflects carrier support only.

## `operational` on a channel

On this scope `operational` asks for more than the project one does: **no incomplete blocker step *and* at least one reachable country.**

That second clause is not redundant. Holding a sender is not the same as being able to deliver with it: an RCS agent with no accepted registration completes `add-agent` and still reaches nobody. `operational` claims capability, so it answers to reach.

> **Tip**: Before a send, `operational` plus `reach.reachableCountries` is the whole pre-flight: the first says the channel works, the second says where. If you also need to know whether there is anyone there, [count the audience](/platform-api/product-api/audience/counting-and-retrieval#counting).

## What a country requires before you get there

`reach` tells you where this project can arrive **today**. It doesn't tell you what a
country asks for — the paperwork, who files it, how long it takes, whether it costs
anything — and that is exactly what you need when a country is missing from the list and
you want it in.

Those rules are documented once, for the dashboard and for the API alike:

- [Countries](/platform/en/channels/countries) - Every destination, with what it asks for on each channel.
- [Coverage & delivery](/platform/en/channels/sms/coverage-and-delivery) - What happens on SMS while a registration is still being filed.

### Asking the API instead

Those pages say what a country asks of anyone. Two endpoints say what it still asks of **one sender in this project**:

[`GET /v1/project/{project}/channel/registration-progress` - One row per sender and country that has recorded paperwork, with how much of it the customer can act on right now.](/platform-api/product-api/reference)

[`GET /v1/project/{project}/channel/{channel}/sender/{id}/register/{country}/checklist` - The steps one country still asks of this sender, and which of them are startable today.](/platform-api/product-api/reference)

Start with the progress endpoint, always. Most destinations record no paperwork at all, so it is the only thing that tells you which sender-and-country pairs are worth a checklist call; a country that publishes nothing is **left out of the rows** rather than returned as zeroes, because "nothing to do here" and "nothing is written up for this country" are different answers.

> **Warning**: **Those steps are not the `steps` on this report.** The ones above are product setup — add a sender, send something — and the customer clears them in the dashboard. The ones on the checklist are a country's **paperwork**: sign a letter, allowlist a verifier, email an operator. A project can be fully `operational` here and still owe one country a signed letter, so never merge the two into a single list.

---

This is one page of the Instasent documentation. For the complete machine-readable index of every guide and API reference, fetch https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt — start there for full context.
