Interactive Message Patterns
Interactive messages — quick-reply buttons, list pickers, and call-to-action buttons — turn open-ended chat into tap-to-respond flows. They reduce typing errors and speed up resolution.
🚀 Quick Start
curl -X POST https://api.afriroute.ai/api/v1/whatsapp/send \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+254712345678",
"type": "interactive",
"interactive": {
"type": "button",
"body": "How can we help today?",
"buttons": [
{"id": "track", "title": "Track order"},
{"id": "support", "title": "Talk to agent"}
]
}
}'
🧩 Choosing the Right Control
| Control | Max options | Best for |
|---|---|---|
| Quick-reply buttons | 3 | Yes/no, top 2–3 actions |
| List message | 10 (sections) | Menus, categories, FAQs |
| CTA URL button | 1 | Open a link, pay, view docs |
Use buttons for the primary path and a list when there are too many options for buttons.
📋 List Messages
await sendWhatsApp({
to: '+234803000000',
type: 'interactive',
interactive: {
type: 'list',
body: 'Pick a service',
button: 'View services',
sections: [{
title: 'Banking',
rows: [
{ id: 'balance', title: 'Check balance' },
{ id: 'transfer', title: 'Send money' },
{ id: 'statement', title: 'Statement' }
]
}]
}
});
🔗 CTA Buttons
send_whatsapp(
to='+254712345678',
type='interactive',
interactive={
'type': 'cta_url',
'body': 'Your invoice is ready.',
'action': {'name': 'View invoice', 'url': 'https://pay.example.com/inv/123'}
}
)
🎯 UX Patterns
- Lead with the common path. Put the 1–2 most-likely actions as buttons.
- Label by outcome, not jargon. "Track order" beats "Logistics".
- Keep titles short. Buttons truncate around 20 characters.
- Always offer an escape. Include "Talk to agent" or "Main menu".
- Echo the choice. Confirm the selection before acting on it.
🔁 Handling Responses
Replies arrive on your webhook with the option id you set.
app.post('/webhooks/whatsapp', (req, res) => {
const reply = req.body.interactive?.button_reply || req.body.interactive?.list_reply;
if (reply?.id === 'support') routeToHuman(req.body.from);
res.sendStatus(200);
});
💡 Best Practices
- Never exceed the option limits — extra options are dropped silently.
- Use stable IDs, not titles, to branch your logic.
- Avoid deep button chains — collapse to a list at 4+ choices.
- Provide a text fallback for clients that can't render interactive content.
- Confirm destructive actions with an explicit button.
📚 Related Resources
Last Updated: May 2026