UC-005 — Multi-Channel Send with Automatic Fallback
| Field | Value |
|---|---|
| ID | UC-005 |
| Goal | Send a message on WhatsApp with automatic fallback to RCS and SMS |
| Channel | WhatsApp -> RCS -> SMS |
| Complexity | Intermediate |
| Estimated time | 15 minutes |
| APIs involved | POST /api/message-server/whatsapp/send, GET /api/partner-gateway/v1/messages/status/{customerMessageId} |
Real-world scenarios
- Banca Adriatica — Transaction notification: The bank notifies the account holder of a suspicious transaction. WhatsApp priority for a rich message with confirm/block buttons, SMS fallback to guarantee receipt even if the customer does not use WhatsApp.
- TelcoMobile — Billing reminder: Invoice due date reminder with payment link. WhatsApp for the attached document, SMS as a safety net.
- FarmaExpress — Order ready: The online pharmacy notifies that the order is ready for pickup. WhatsApp with a pickup point map, SMS with a text address as fallback.
Prerequisites
Before you begin, make sure you have:
- Active API Key → How to get one
- Sufficient credit → Check in the Qlara Dashboard
- WhatsApp
phoneNumberId+ RCSagentId+ SMS sender
:::tip Test without costs
Add "simulation": true in the request body to validate the flow without actually sending messages and without consuming credit.
:::
Fallback flow
The diagram illustrates the fallback chain: the system first tries WhatsApp, then RCS if available, and finally SMS as a last resort.
Step 1 — Compose the message with fallback chain
The request body includes the main message (WhatsApp) and two fallback objects: fallbackRcs for RCS and fallbackSms for SMS.
:::info Important rule
If you specify fallbackRcs, you must also include fallbackSms. You can, however, use only fallbackSms without RCS for a direct WhatsApp -> SMS fallback.
:::
Body structure
| Field | Type | Required | Description |
|---|---|---|---|
destination | string | Yes | Number in international format (e.g. +393401234567) |
phoneNumberId | integer | Yes | Sender WhatsApp Business number ID |
template | object | Yes* | Meta-approved template (*alternative to body) |
placeholders | object | No | Values to substitute in the template |
fallbackRcs.agentId | integer | Yes | Sender RCS agent ID |
fallbackRcs.templateId | integer | Yes* | RCS template (*alternative to body) |
fallbackSms.sender | string | Yes | SMS sender (alphanumeric or numeric) |
fallbackSms.text | string | Yes | SMS fallback message text |
Step 2 — Send the message
Call the WhatsApp endpoint with the complete fallback chain.
curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"nome": "Giulia",
"importo": "1.250,00",
"data": "09/04/2026"
},
"enableNotification": true,
"messageId": "txn-notifica-20260409-001",
"fallbackRcs": {
"agentId": 1,
"templateId": 10
},
"fallbackSms": {
"sender": "BancaAdri",
"text": "Gentile Giulia, e stata registrata una transazione di EUR 1.250,00 in data 09/04/2026. Se non riconosci questa operazione, chiama il numero verde 800.123.456."
}
}'
Response — WhatsApp accepted
{
"messageId": "txn-notifica-20260409-001",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
},
"rcs": null,
"sms": null
}
}
When WhatsApp accepts the message, the rcs and sms fields remain null because the fallback was not triggered.
Response — Fallback activated down to SMS
{
"messageId": "txn-notifica-20260409-001",
"simulation": false,
"results": {
"whatsapp": {
"accepted": false
},
"rcs": {
"accepted": false,
"reasons": ["AGENT_NOT_REACHABLE"]
},
"sms": {
"accepted": true,
"unicode": false,
"parts": 2,
"reasons": []
}
}
}
Behind the scenes — How the fallback chain works
- WhatsApp attempt: The message is forwarded to Meta via WhatsApp Business API. If the recipient number is registered on WhatsApp and the template is approved, the message is accepted.
- RCS fallback: If WhatsApp fails (unregistered number, rejected template, network error), the system automatically tries RCS using the provided
agentIdandtemplateId. - SMS fallback: If RCS also fails (incompatible device, unreachable agent), the system sends an SMS with the specified
senderandtext.
Each level is independent: you can receive separate delivery callbacks for the channel that actually delivered. The messageId stays the same throughout the chain, enabling end-to-end correlation.
Step 3 — Check which channel delivered
After a few seconds, query the delivery status to find out which channel actually delivered the message.
curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/messages/status/txn-notifica-20260409-001?channel=SMS" \
-H "X-Api-Key: YOUR_API_KEY"
Response — Delivered via SMS
{
"customerMessageId": "txn-notifica-20260409-001",
"channel": "SMS",
"destination": "+393401234567",
"deliveryStatus": "DELIVERED",
"deliveryStatusDescription": "Message delivered to handset",
"sendDate": "2026-04-09T10:15:00+02:00",
"deliveryDate": "2026-04-09T10:15:04+02:00",
"readDate": null
}
The channel field indicates which channel actually delivered the message.
Variant — Direct WhatsApp -> SMS fallback (without RCS)
If you do not have an RCS agent configured, you can skip the intermediate level by omitting fallbackRcs:
curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393489876543",
"phoneNumberId": 5,
"template": {
"id": 55
},
"placeholders": {
"cliente": "Marco Bianchi",
"scadenza": "15/04/2026",
"importo": "89,90"
},
"fallbackSms": {
"sender": "TelcoMob",
"text": "Gentile Marco Bianchi, la sua fattura di EUR 89,90 scade il 15/04/2026. Acceda all area clienti per il pagamento."
}
}'
{
"messageId": "d3f8a1b2-c4e5-6789-abcd-ef0123456789",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
},
"rcs": null,
"sms": {
"accepted": true,
"unicode": false,
"parts": 1,
"reasons": []
}
}
}
Common errors
All channels fail
If no channel can accept the message, the response indicates accepted: false for every level:
{
"messageId": "txn-notifica-20260409-002",
"simulation": false,
"results": {
"whatsapp": {
"accepted": false
},
"rcs": {
"accepted": false,
"reasons": ["AGENT_NOT_REACHABLE"]
},
"sms": {
"accepted": false,
"reasons": ["INVALID_DESTINATION"]
}
}
}
Corrective actions table
| Situation | Action |
|---|---|
| All channels reject | Verify the recipient number and retry |
| Only SMS fails | Check the sender ID and text (length, special characters) |
| WhatsApp rejected, RCS/SMS ok | The recipient may not have WhatsApp — the fallback is working correctly |
422 error | Template not approved or invalid phoneNumberId |
429 error | Rate limit exceeded — wait and retry |
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | Compose body with fallbackRcs + fallbackSms | Fallback chain configured |
| 2 | POST /whatsapp/send | messageId returned, at least one channel accepted: true |
| 3 | GET /messages/status/{id} | channel indicates the channel that delivered |
Next steps
- UC-008 — Delivery Tracking with Webhooks: Receive real-time updates on which channel delivered
- WhatsApp Guide: Deep dive into templates, media, and the 24-hour window
- Channel Overview: Compare SMS, RCS, and WhatsApp to choose the right strategy