Channel Routing and Fallback Behavior in the Sent API
Channel routing selects the channel (sms, whatsapp, or rcs) 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. |
- 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.
- 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. The winner is the best-matching rule under the preceding criteria; whether that is an SMS or a WhatsApp route depends on which routes exist for your account and the recipient. If no rule matches, the message fails without a channel; see Messages with channel auto.
Pinned Channels
A pinned entry (sms, whatsapp, or rcs) 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.
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
FILTEREDwith the internal codeERR_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, provider service unavailable, provider timeout, or a transport error. All other failures stayFAILED. - 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 | Internal error code |
|---|---|---|
FAILED | No routing rule matched the send: no route covers this recipient for your account | ERR_NO_ROUTE_MATCHED |
FAILED | Required template variables missing or invalid (pre-routing validation) | ERR_TEMPLATE_PARAMS_INVALID |
FILTERED | Pre-routing consent gate: the recipient opted out or the number is on your suppression list | ERR_CONSENT_BLOCKED |
BLOCKED | Account precondition gate: insufficient balance, an onboarding quota, or an unapproved template | Varies |
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 internal ERR_* code is recorded on the message but is not included in API responses or webhook payloads. See Error handling for the full list of send-time error codes, or contact support@sent.dm with the message id for the exact reason.
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.