SMS fallback & priority

Make sure important messages get through. Zend can automatically fall back between SMS and WhatsApp when the first channel can't deliver, and lets you set queue priority and schedule sends — all on the same POST /messages request.

POST/messages

Automatic fallback

Fallback is driven by the order of preferred_channels. List the channels to try, in order: Zend sends on the first, and if it terminally fails, automatically advances to the next — reversing the first channel's charge so you're only ever billed for the channel that actually delivered.

curl -X POST https://api.tryzend.com/messages \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+233593152134",
    "body": "Important notification: Your order has been shipped!",
    "preferred_channels": ["sms", "whatsapp"],
    "template_id": "tmpl_order_update"
  }'

Here Zend tries SMS first; if it fails, it falls back to WhatsApp. The direction follows the array exactly — reverse it to ["whatsapp", "sms"] to try WhatsApp first and fall back to SMS. To turn fallback off, list a single channel.

Note

Fallback direction is just the order you list: ["sms","whatsapp"] is SMS→WhatsApp, ["whatsapp","sms"] is WhatsApp→SMS. There is no separate on/off flag — the presence of a second channel is what enables fallback.

Warning

A WhatsApp leg always requires an approved template_id (Meta requires business-initiated WhatsApp messages to use an approved template). Include one whenever whatsapp appears in preferred_channels. The SMS leg still uses your plain body (or the template's SMS variant).

Request fields

preferred_channelsstring[]
Channels to attempt, in order — supported values are sms and whatsapp. The first is tried first; any that follow are fallbacks. Defaults to ["sms"].
template_idstring
An approved template. Required when whatsapp appears in preferred_channels.
template_paramsobject
Values for the template's variables, e.g. { "1": "Ada", "2": "#1234" }.

Note

The channel that actually delivered a message is reported as channel_used when you check status. See SMS delivery & webhooks.

Message priority

priority controls how quickly a message is picked up from the queue for processing. It is independent of channel selection.

{
  "to": "+233593152134",
  "body": "URGENT: System maintenance in 30 minutes",
  "preferred_channels": ["sms"],
  "priority": "urgent"
}

Levels, from lowest to highest: low, normal, high, urgent. Defaults to normal.

Scheduling

Set scheduled_for to an ISO 8601 timestamp to send a message at a specific time instead of immediately.

{
  "to": "+233593152134",
  "body": "Reminder: Your appointment is in 1 hour",
  "preferred_channels": ["sms"],
  "scheduled_for": "2024-01-15T13:00:00Z"
}

Request fields

prioritystring
Queue priority: low, normal, high, or urgent. Defaults to normal.
scheduled_forstring
ISO 8601 timestamp (UTC) for when the message should be sent. Omit to send immediately.

Cost control

To keep a message on the cheapest channel only, list a single channel so it is never re-attempted on a pricier one:

{
  "to": "+233593152134",
  "body": "Your monthly statement is ready",
  "preferred_channels": ["sms"]
}

Tips for keeping SMS costs down:

  • List only ["sms"] for non-critical messages so they never fall back to a more expensive channel.
  • Keep messages under 160 characters — each additional part is billed at the full SMS rate.
  • Reserve multi-channel fallback for messages that genuinely justify the extra cost, like OTPs.

Deprecated fields

Earlier versions of this API used two fields that are no longer needed:

  • fallback_enabled (boolean) — fallback is now controlled entirely by the preferred_channels order, so this has no effect.
  • delivery_priority (cost / speed / reliability) — channels are ordered by preferred_channels and pricing is fixed per channel, so this has no effect.

Both are still accepted for backward compatibility (they won't cause an error) but are ignored. You can safely remove them from your requests.

Next steps