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:

ValueBehavior
sentAuto-detect: routing selects the channel per recipient at send time. Default when channel is omitted.
smsPins the message to SMS.
whatsappPins the message to WhatsApp.
rcsPins the message to RCS.
  • Omitting channel or sending an empty array is equivalent to ["sent"].
  • Any other value fails request validation and the request is rejected with a 400 error.
  • 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 no fallback field; fallback is a property of routing, described below.
  • The 202 response echoes the request per message in recipients[].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:

  1. Rules pinned to the exact recipient number rank ahead of all others.
  2. Rules scoped to your account rank ahead of global rules.
  3. Match specificity: the share of the send's attributes the rule explicitly matches, highest first.
  4. Rule priority, highest first.
  5. Longer (more specific) recipient number prefix.
  6. 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 FILTERED with the internal code ERR_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 FAILED delivery 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 stay FAILED.
  • 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 QUEUED and ROUTED transitions 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:

SurfaceBefore a route is chosenAfter a route is attempted
POST /v3/messages response, recipients[].channelsent for auto-detect entries, otherwise the pinned channelNot updated; the response is returned at accept time
message.queued, message.routed, and message.scheduled webhooks, payload.channelsent for auto-detect sends, otherwise the pinned channelFire again on a reroute
Terminal webhooks (message.sent, message.delivered, message.read, message.failed, message.filtered, message.blocked), payload.channelauto when the send ends before any route was chosenThe channel of the attempted route
GET /v3/messages/{id}, channel fieldauto for auto-detect sends, otherwise the pinned channelThe 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 statusCauseInternal error code
FAILEDNo routing rule matched the send: no route covers this recipient for your accountERR_NO_ROUTE_MATCHED
FAILEDRequired template variables missing or invalid (pre-routing validation)ERR_TEMPLATE_PARAMS_INVALID
FILTEREDPre-routing consent gate: the recipient opted out or the number is on your suppression listERR_CONSENT_BLOCKED
BLOCKEDAccount precondition gate: insufficient balance, an onboarding quota, or an unapproved templateVaries

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.

On this page