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 UNKNOWN status (still in flight, no delivery receipt) 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.
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:

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. A read is not a status: the message stays DELIVERED, and you detect the read through the READ webhook event or through readDate, which WhatsApp fills in.

Step 1 — Send the primary message on WhatsApp​

Send the promotional message on WhatsApp:

curl -X POST https://api.qlara.ai/api/message-server/whatsapp/send \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"destination": "+393471234567",
"phoneNumberId": 5,
"template": {
"id": 91
},
"placeholders": {
"firstName": "Marco"
},
"enableNotification": true
}'

phoneNumberId is your WhatsApp Business number and template.id the approved template promo_saldi_inverno, whose text already carries the discount and the end date: only {firstName} is filled in at send time.

Response — Message accepted​

{
"messageId": "b8f3a21c-7d44-4e19-9a1b-3c5d7e9f0a12",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
}
}
}
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://api.qlara.ai/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": "UNKNOWN",
"deliveryStatusDescription": "unknown",
"sendDate": "2026-04-09T10:00:00+02:00",
"deliveryDate": null,
"readDate": 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 on WhatsApp are:

  • ERROR (statusCode 9): delivery failed, retry immediately
  • EXPIRED (statusCode 4): validity window elapsed, retry immediately
  • DISABLED (statusCode 10): the recipient has WhatsApp switched off, retry immediately
  • UNSUPPORTED (statusCode 11): the number does not support WhatsApp, retry immediately
  • CONVERSATION_CLOSED (statusCode 12): the 24-hour customer-service window had closed, retry immediately
  • UNKNOWN after timeout: the message is still in flight with no delivery receipt (WhatsApp has no intermediate status), likely no WhatsApp

Step 3 — Send the fallback on SMS​

If the status is not DELIVERED after the timeout (a message that has been read keeps the DELIVERED status), adapt the content and send via SMS:

curl -X POST https://api.qlara.ai/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 } } }
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://api.qlara.ai/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}?channel=WHATSAPPdeliveryStatus: "UNKNOWN" (not delivered after timeout)
3POST /sms/sendNew messageId, accepted: true
4GET /messages/status/{id}?channel=SMSdeliveryStatus: "DELIVERED" on SMS

Complete end-to-end example​

#!/bin/bash
# Re-engagement workflow: WhatsApp → SMS fallback
API_KEY="YOUR_API_KEY"
BASE_URL="https://api.qlara.ai"
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","phoneNumberId":5,"template":{"id":91},"placeholders":{"firstName":"Marco"},"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" ]]; then # a read message stays DELIVERED
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​

The send API answers 400 Bad Request: a template that is not APPROVED is reported as not found.

{ "status": "fail", "message": "WhatsApp Template not found", "code": 33 }

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​