UC-027 — Re-engagement Workflow (Retry on Different Channel)
| Field | Value |
|---|---|
| ID | UC-027 |
| Goal | Resend a message on an alternative channel if the first attempt fails |
| Channel | WhatsApp → SMS (manual fallback) |
| Complexity | ⭐⭐⭐ Advanced |
| Estimated time | 20 minutes |
| APIs involved | POST /api/message-server/whatsapp/send, GET /api/partner-gateway/v1/messages/status/{customerMessageId}, POST /api/message-server/sms/send |
Real-world scenarios
- FashionOutlet — Undelivered promo: The WhatsApp promotional message for the winter sales is not delivered (user without WhatsApp). The system detects the failure and automatically sends an SMS with the same content.
- ClinicaSalute — Appointment reminder: The reminder sent via WhatsApp remains in SENT status for over 2 hours. The application decides to send a backup SMS to ensure the patient receives the notice.
- BancaSicura — Payment expiry notification: The payment due notice sent on WhatsApp fails. The system escalates to SMS within 30 minutes to ensure timely reception.
:::info Difference from UC-005 (Multi-Channel Fallback) In UC-005 the fallback is automatic: the gateway manages the WhatsApp → RCS → SMS chain transparently. In this UC-027, the fallback is manual and controlled by your application: you decide when, how and on which channel to retry. This approach is useful when you want to apply custom logic (different wait times, channel-adapted content, budget limits). :::
Prerequisites
Before you begin, make sure you have:
- Active API Key → How to get one
- Sufficient credit → Check in the Qlara Dashboard
- At least two channels configured (WhatsApp + SMS)
:::tip Test without costs
Add "simulation": true in the request body to validate the flow without actually sending messages and without consuming credit.
:::
Re-engagement flow
The diagram illustrates the decision flow: your application sends on WhatsApp, waits for the result, and in case of failure adapts the content and retries on SMS.
Step 1 — Send the primary message on WhatsApp
Send the promotional message on WhatsApp:
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": "+393471234567",
"sender": "+393801234567",
"content": {
"templateName": "promo_saldi_inverno",
"language": "it",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Marco" },
{ "type": "text", "text": "30%" },
{ "type": "text", "text": "15 aprile" }
]
}
]
},
"enableNotification": true
}'
Response — Message accepted
{
"messageId": "b8f3a21c-7d44-4e19-9a1b-3c5d7e9f0a12",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true,
"reasons": []
}
}
}
:::tip Save the messageId and timestamp
Save the messageId and the send time in your database. You will need them for polling and to calculate the wait timeout before retrying.
:::
Step 2 — Wait and check the delivery status
After a reasonable interval (e.g., 2 hours for promotional messages, 30 minutes for urgent notifications), check the status:
curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/messages/status/b8f3a21c-7d44-4e19-9a1b-3c5d7e9f0a12?channel=WHATSAPP" \
-H "X-Api-Key: YOUR_API_KEY"
Response — Message not delivered
{
"customerMessageId": "b8f3a21c-7d44-4e19-9a1b-3c5d7e9f0a12",
"channel": "WHATSAPP",
"destination": "+393471234567",
"deliveryStatus": "SENT",
"deliveryStatusDescription": "Message sent but not delivered to device",
"sendDate": "2026-04-09T10:00:00+02:00",
"deliveryDate": null
}
Behind the scenes — When to trigger the fallback
The decision of when to trigger the retry depends on the message type:
| Message type | Suggested timeout | Reasoning |
|---|---|---|
| Promotional | 2-4 hours | User might read later, not urgent |
| Appointment reminder | 30-60 minutes | Must arrive in time |
| Security notification | 10-15 minutes | Critical, requires immediate delivery |
| Billing/payment due | 1-2 hours | Important but not immediately critical |
The statuses indicating failure are:
ERROR(statusCode 6): definitive error, retry immediatelyEXPIRED(statusCode 8): TTL exceeded, retry immediatelySENTafter timeout: message sent but not delivered, likely no WhatsApp
Step 3 — Send the fallback on SMS
If the status is not DELIVERED or READ after the timeout, adapt the content and send via SMS:
curl -X POST https://lora-api.agiletelecom.com/api/message-server/sms/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"sender": "FashionOut",
"body": "Ciao Marco! Saldi invernali FashionOutlet: -30% su tutto fino al 15 aprile. Scopri le offerte: https://fashionoutlet.it/saldi Rispondi STOP per non ricevere più messaggi.",
"campaignId": "saldi-inverno-2026-retry",
"enableNotification": true
}'
Response — SMS accepted
{ "messageId": "c9a4b32d-8e55-4f20-ab2c-4d6e8f0a1b23", "simulation": false, "results": { "sms": { "accepted": true, "parts": 1 } } }
:::note Adapt the content for the channel SMS text has different limits compared to WhatsApp. Remove rich formatting, shorten links and always include the opt-out option. :::
Step 4 — Verify the final delivery
Check the fallback SMS status:
curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/messages/status/c9a4b32d-8e55-4f20-ab2c-4d6e8f0a1b23?channel=SMS" \
-H "X-Api-Key: YOUR_API_KEY"
Response — Delivered
{ "customerMessageId": "c9a4b32d-8e55-4f20-ab2c-4d6e8f0a1b23", "channel": "SMS", "deliveryStatus": "DELIVERED", "deliveryDate": "2026-04-09T12:05:02+02:00" }
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | POST /whatsapp/send | messageId returned, accepted: true |
| 2 | GET /messages/status/{id} | deliveryStatus: "SENT" (not delivered after timeout) |
| 3 | POST /sms/send | New messageId, accepted: true |
| 4 | GET /messages/status/{id} | deliveryStatus: "DELIVERED" on SMS |
Complete end-to-end example
#!/bin/bash
# Re-engagement workflow: WhatsApp → SMS fallback
API_KEY="YOUR_API_KEY"
BASE_URL="https://lora-api.agiletelecom.com"
TIMEOUT_SECONDS=7200 # 2 hours for promotional messages
# 1. Send WhatsApp
WA_ID=$(curl -s -X POST "${BASE_URL}/api/message-server/whatsapp/send" \
-H "Content-Type: application/json" -H "X-Api-Key: ${API_KEY}" \
-d '{"destination":"+393471234567","sender":"+393801234567","content":{"templateName":"promo_saldi_inverno","language":"it","components":[{"type":"body","parameters":[{"type":"text","text":"Marco"},{"type":"text","text":"30%"},{"type":"text","text":"15 aprile"}]}]},"enableNotification":true}' | jq -r '.messageId')
# 2. Wait and check
sleep ${TIMEOUT_SECONDS}
STATUS=$(curl -s -X GET "${BASE_URL}/api/partner-gateway/v1/messages/status/${WA_ID}?channel=WHATSAPP" \
-H "X-Api-Key: ${API_KEY}" | jq -r '.deliveryStatus')
# 3. If not delivered, retry on SMS
if [[ "$STATUS" != "DELIVERED" && "$STATUS" != "READ" ]]; then
SMS_ID=$(curl -s -X POST "${BASE_URL}/api/message-server/sms/send" \
-H "Content-Type: application/json" -H "X-Api-Key: ${API_KEY}" \
-d '{"destination":"+393471234567","sender":"FashionOut","body":"Ciao Marco! Saldi invernali: -30% fino al 15 aprile. https://fashionoutlet.it/saldi","campaignId":"saldi-inverno-2026-retry"}' | jq -r '.messageId')
echo "Retry SMS sent: ${SMS_ID}"
fi
Variants
Retry with escalation to three channels
Add RCS as an intermediate level: WhatsApp → RCS → SMS. After the WhatsApp failure, try POST /rcs/send before falling back to SMS.
Retry with content differentiated by urgency
For critical notifications (e.g., bank security), reduce the timeout to 10 minutes and use an SMS text with an urgent tone.
Common errors
WhatsApp — Template not approved
{ "results": { "whatsapp": { "accepted": false, "reasons": ["Template not approved or not found"] } } }
Solution: Verify that the template has been approved by Meta (see UC-013).
Double delivery
If the WhatsApp message is delivered after the SMS retry, the user will receive the message on both channels. Use appropriate timeouts for the message type (see the table in Step 2).
Next steps
- UC-005 — Automatic Multi-Channel Fallback: Compare with gateway-managed fallback
- UC-004 — Check Delivery Status: Learn more about polling and status codes
- UC-008 — Delivery Tracking via Webhook: Use webhooks for real-time decisions
- SMS Universal Guide: Complete SMS channel documentation