Channel Routing and Fallback Behavior in the Sent API
Channel routing selects the channel (sms, whatsapp, rcs, or mms) and the underlying provider for every message accepted by POST /v3/messages. This page defines the accepted channel values, the resolution rules behind the default sent auto-detect channel, fallback behavior, and where the resolved channel appears in API responses, message records, and webhooks.
For the design rationale behind auto-detection, see Unified Messaging Intelligence. For what each channel supports, see Channels.
Channel Values
POST /v3/messages accepts channel as an array of strings. Allowed values:
| Value | Behavior |
|---|---|
sent | Auto-detect: routing selects the channel per recipient at send time. Default when channel is omitted. |
sms | Pins the message to SMS. |
whatsapp | Pins the message to WhatsApp. |
rcs | Pins the message to RCS. |
mms | Pins the message to MMS. Requires allowMms on the account; see MMS. |
- Omitting
channelor sending an empty array is equivalent to["sent"]. - Any other value fails request validation and the request is rejected with a
400error. - The array is a broadcast list, not a fallback priority list. Each entry creates a separate message per recipient:
"channel": ["whatsapp", "sms"]with two recipients creates four messages. There is nofallbackfield; fallback is a property of routing, described below. - The
202response echoes the request per message inrecipients[].channel. Auto-detect entries appear as"sent".
curl -X POST https://api.sent.dm/v3/messages \
-H "x-api-key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": ["+14155551234"],
"template": { "name": "order_confirmation", "parameters": { "name": "John" } }
}'{
"success": true,
"data": {
"status": "QUEUED",
"template_id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
"template_name": "order_confirmation",
"recipients": [
{
"message_id": "8ba7b830-9dad-11d1-80b4-00c04fd430c8",
"to": "+14155551234",
"channel": "sent",
"body": "Hi John, your order has been confirmed."
}
]
},
"error": null,
"meta": {
"request_id": "req_7X9zKp2jDw",
"timestamp": "2026-07-25T10:30:00Z",
"version": "v3"
}
}How Auto-Detect Resolves a Channel
A message on the sent channel is matched against routing rules at send time, after the request has already been accepted with 202. Routing rules are created and maintained by the platform from your channel setup:
- Connecting a WhatsApp Business account creates an account-scoped WhatsApp route.
- Activating a phone number for a destination country creates account-scoped SMS routes for that country.
- A US
TEN_DLCorLOCALnumber also carries your traffic to the six US territories: Puerto Rico (PR), the US Virgin Islands (VI), Guam (GU), American Samoa (AS), the Northern Mariana Islands (MP), and the US Minor Outlying Islands (UM). Activating it creates a route for each, on the same number. Those routes never fall back to another sender, because a 10DLC number may carry only its own brand's traffic. - Where a territory accepts alphanumeric senders, Sent sets one up for your account the first time you send there, before the message routes. It ranks ahead of the 10DLC route and falls back to it, so the alphanumeric sender is tried first and your number is the last resort. Sent never sets one up automatically in the US or Canada, because their carriers don't deliver alphanumeric traffic.
- Global rules (scoped to no account) apply to all accounts. A send never matches another account's rules.
A rule matches when every dimension it constrains matches the send; a dimension the rule leaves unset matches anything. Rules can constrain the recipient (country, number prefix, exact number, carrier, number type, ported state), the sender, the template (id, name, category), the channel, and whether the send is international.
Matching rules form an ordered candidate list. The ordering criteria, applied in sequence:
- Rules pinned to the exact recipient number rank ahead of all others.
- Rules scoped to your account rank ahead of global rules.
- Match specificity: the share of the send's attributes the rule explicitly matches, highest first.
- Rule priority, highest first.
- Longer (more specific) recipient number prefix.
- Older rule first.
Rules that are inactive, deleted, or expired are excluded, as are rules whose own minimum match threshold is not met. Candidates on a channel where the message's template carries an explicit non-approved review status (for example rejected, pending, or paused) are dropped; a channel with no per-channel review recorded is not blocked.
The first candidate wins: the message transitions to ROUTED, a message.routed webhook fires, and the send dispatches on the winning route. The remaining candidates stay available as fallback routes.
Auto-detect applies no fixed channel preference order among rules. The winner is the best-matching rule under the preceding criteria. However, before rules are ordered, the send's content decides which channels are even eligible: a message with no attachment is ineligible for MMS, and any MMS candidate is removed from its list regardless of rules. See Media and MMS eligibility. If no rule matches, the message fails without a channel; see Messages with channel auto.
Media and MMS Eligibility
Routing cannot see message content, so MMS eligibility is decided before rules are ordered rather than by a rule dimension.
- A message carrying no attachment is not eligible for MMS on auto-detect. Any MMS candidate is removed from its list, so a text-only send is never billed as MMS, even from an account with an active MMS route.
- A message with attachments, to a recipient in a covered market, on a template approved for MMS, keeps its MMS candidate. That candidate mirrors the SMS route on the same sender at a higher priority, so auto-detect prefers MMS over SMS on that number.
- If the market is not covered or the template is not approved for MMS, the candidate is dropped and the message resolves to another channel, usually SMS. An MMS candidate that fails after routing chose it, such as one whose attachment is over 600 KB, falls through the same way.
- On SMS, the attachment URL is appended to the text as a link when it fits without adding a billed segment. Otherwise the SMS carries the text alone.
This filter only applies on auto-detect. When you name a channel explicitly (channel: ["mms"]), your choice is honored: a text-only pinned MMS is delivered as a carrier MMS with no attachment. The carrier renders it differently from SMS on the handset.
Attachments are supplied per send with media_urls, or carried by the template's mms body (see Template Definition). For the full MMS sending guide, see MMS.
Pinned Channels
A pinned entry (sms, whatsapp, rcs, or mms) restricts matching to routes on that channel. Rules without a channel constraint still match and resolve to the pinned channel.
- A pinned send never falls back to a different channel. Fallback between routes on the same channel (for example, an SMS provider hop) remains possible when the rule permits it.
- If no route exists on the pinned channel, the message fails with no route matched, even when another channel could deliver to the recipient.
- Pinning
mmsadditionally requiresallowMmson the account. If the flag is off, the message fails withchannel_unavailablerather than falling back to SMS.
Fallback
At Send Time
Fallback walks the resolved candidate list in order:
- The winning candidate is attempted first. Each attempted route is recorded as a delivery attempt on the same message.
- If submission to the provider fails and the candidate's rule allows fallback, the next candidate is attempted, repeating down the list.
- A DENY rule that allows fallback passes the send to the next candidate.
- A DENY rule that does not allow fallback ends the send as
FILTEREDwithreason_codeDELIVERY_004(internallyERR_ROUTE_DENIED), as does a candidate list in which every route is denied. The message record carries the denied route's channel.
After a Delivery Failure
A message that a provider accepted and later reported as failed can re-enter routing:
- A terminal
FAILEDdelivery receipt triggers a reroute only when its error signals a route or carrier failure another route might overcome: undeliverable by this route, the carrier refusing the sender itself (for example, a network that doesn't accept alphanumeric senders), no route available to the destination network, provider service unavailable, provider timeout, or a transport error. All other failures stayFAILED, including an invalid number, an unreachable handset, a temporary carrier error, rate limiting, and carrier filtering. - Each reroute is a separate send attempt and is charged as one.
- A WhatsApp message that Meta accepts and then reports as failed for recipient-side reasons is rerouted the same way, and a recipient-scoped rule records that WhatsApp is not deliverable for that number. This is the path behind WhatsApp-to-SMS fallback on auto-detect sends.
- A reroute excludes every route already attempted and re-runs the send pipeline on the same message id, so the
QUEUEDandROUTEDtransitions and their webhooks fire again. - A message attempts at most 3 distinct routes (channel and provider pairs) across its initial send and all reroutes.
- Consent gates re-apply on every reroute; an opted-out recipient never receives a rerouted message.
Where the Resolved Channel Appears
Internally, a message that has not yet resolved a route carries the placeholder channel auto. Public surfaces expose it as follows:
| Surface | Before a route is chosen | After a route is attempted |
|---|---|---|
POST /v3/messages response, recipients[].channel | sent for auto-detect entries, otherwise the pinned channel | Not updated; the response is returned at accept time |
message.queued, message.routed, and message.scheduled webhooks, payload.channel | sent for auto-detect sends, otherwise the pinned channel | Fire again on a reroute |
Terminal webhooks (message.sent, message.delivered, message.read, message.failed, message.filtered, message.blocked), payload.channel | auto when the send ends before any route was chosen | The channel of the attempted route |
GET /v3/messages/{id}, channel field | auto for auto-detect sends, otherwise the pinned channel | The channel of the attempted route |
Webhook payload shapes are documented in Webhook event types; the status lifecycle is documented in Message status tracking.
Messages With Channel auto
A terminal message whose channel is auto ended before routing chose a channel. This occurs only on auto-detect sends; a pinned send keeps its pinned channel in every state.
| Terminal status | Cause | reason_code |
|---|---|---|
FAILED | No routing rule matched the send: no route covers this recipient for your account | DELIVERY_003 |
FAILED | Required template variables missing or invalid (pre-routing validation) | VALIDATION_008 |
FILTERED | Pre-routing consent gate: the recipient opted out or the number is on your suppression list | BUSINESS_004 |
BLOCKED | Account precondition gate: insufficient balance, an onboarding quota, or an unapproved template | BUSINESS_003, BUSINESS_020 or BUSINESS_005 |
A FAILED message on channel auto with no route matched means the recipient is not covered by any channel that is set up for your account. Routes exist once the corresponding channel setup is complete; see Channel setup. Persistent delivery problems are covered in Messages not delivered.
The reason_code and a reason sentence arrive on GET /v3/messages/{id} and on the message's webhook. See Error handling for how the internal ERR_* codes map to them.
Rate Limits
Rate limit values, window semantics, 429 response headers, and per-endpoint limits for the Sent API v3, with the scope rules for shared account pools.
Two-Way Messaging Keywords, Channel Support, and Endpoints
Default and custom keyword actions, exact-match rules, two-way channel support for SMS, RCS, and WhatsApp, and the GET /v3/conversations history endpoints.