Skip to main content

UC-027 — Re-engagement Workflow (Retry on Different Channel)

FieldValue
IDUC-027
GoalResend a message on an alternative channel if the first attempt fails
ChannelWhatsApp → SMS (manual fallback)
Complexity⭐⭐⭐ Advanced
Estimated time20 minutes
APIs involvedPOST /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:

:::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 typeSuggested timeoutReasoning
Promotional2-4 hoursUser might read later, not urgent
Appointment reminder30-60 minutesMust arrive in time
Security notification10-15 minutesCritical, requires immediate delivery
Billing/payment due1-2 hoursImportant but not immediately critical

The statuses indicating failure are:

  • ERROR (statusCode 6): definitive error, retry immediately
  • EXPIRED (statusCode 8): TTL exceeded, retry immediately
  • SENT after 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

StepActionResult
1POST /whatsapp/sendmessageId returned, accepted: true
2GET /messages/status/{id}deliveryStatus: "SENT" (not delivered after timeout)
3POST /sms/sendNew messageId, accepted: true
4GET /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

References