Oui — une liste de 5 lignes (1 à 5), pas des boutons : un message ne porte que 3 boutons ; la note revient dans button_id, sans template dans les 24 h.
Astuce
Oui — une liste de 5 lignes (1 à 5), pas des boutons : un message ne porte que 3 boutons ; la note revient dans button_id, sans template dans les 24 h.
Après un service, vous demandez « Comment était votre visite ? » et le client répond par une note de 1 à 5 en un geste. Votre serveur lit la note dans button_id.
Oui, c'est possible sans template, tant que le client vous a écrit dans les dernières 24 h (le cas de la fin d'un échange : il vient de répondre). Pas avec cinq boutons : un message interactif porte 3 boutons au plus. Pour 5 notes, utilisez une liste de 5 lignes ; pour rester en boutons, passez à 3 niveaux (Bof / Bien / Excellent). Hors des 24 h, un message d'enquête doit être un template.
Vous : Merci pour votre visite Awa. Quelle note nous donnez-vous ?
[ Noter ]
Client : (touche « Noter », la liste s'ouvre)
- 5 · Excellent
- 4 · Bien
- 3 · Moyen
- 2 · Décevant
- 1 · Mauvais
Client : (touche « 4 · Bien »)
Webhook : message.inbound type=text text="4 · Bien" button_id="rate:4"
Vous : Merci pour votre note de 4/5 !
Option A, la liste de 5 lignes (la plus fine) :
curl
curl -X POST "https://wa-api.geskap.com/v1/messages/interactive" \
-H "Authorization: Bearer $GESKAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+237690000001",
"body": "Merci pour votre visite Awa. Quelle note nous donnez-vous ?",
"list": {
"button": "Noter",
"sections": [
{
"rows": [
{ "id": "rate:5", "title": "5 · Excellent" },
{ "id": "rate:4", "title": "4 · Bien" },
{ "id": "rate:3", "title": "3 · Moyen" },
{ "id": "rate:2", "title": "2 · Décevant" },
{ "id": "rate:1", "title": "1 · Mauvais" }
]
}
]
}
}'
Node.js
const res = await fetch("https://wa-api.geskap.com/v1/messages/interactive", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"to": "+237690000001",
"body": "Merci pour votre visite Awa. Quelle note nous donnez-vous ?",
"list": {
"button": "Noter",
"sections": [
{
"rows": [
{ "id": "rate:5", "title": "5 · Excellent" },
{ "id": "rate:4", "title": "4 · Bien" },
{ "id": "rate:3", "title": "3 · Moyen" },
{ "id": "rate:2", "title": "2 · Décevant" },
{ "id": "rate:1", "title": "1 · Mauvais" }
]
}
]
}
}),
});
console.log(res.status, await res.json());
PHP
$ch = curl_init("https://wa-api.geskap.com/v1/messages/interactive");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("GESKAP_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"to" => "+237690000001",
"body" => "Merci pour votre visite Awa. Quelle note nous donnez-vous ?",
"list" => [
"button" => "Noter",
"sections" => [
[
"rows" => [
["id" => "rate:5", "title" => "5 · Excellent"],
["id" => "rate:4", "title" => "4 · Bien"],
["id" => "rate:3", "title" => "3 · Moyen"],
["id" => "rate:2", "title" => "2 · Décevant"],
["id" => "rate:1", "title" => "1 · Mauvais"],
],
],
],
],
]),
]);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $res;
Python
import os, requests
res = requests.request(
"POST",
"https://wa-api.geskap.com/v1/messages/interactive",
headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
json={
"to": "+237690000001",
"body": "Merci pour votre visite Awa. Quelle note nous donnez-vous ?",
"list": {
"button": "Noter",
"sections": [
{
"rows": [
{"id": "rate:5", "title": "5 · Excellent"},
{"id": "rate:4", "title": "4 · Bien"},
{"id": "rate:3", "title": "3 · Moyen"},
{"id": "rate:2", "title": "2 · Décevant"},
{"id": "rate:1", "title": "1 · Mauvais"},
],
},
],
},
},
timeout=15,
)
print(res.status_code, res.json())
Option B, trois boutons (plus rapide, moins précis). L'id garde l'échelle sur 5 : rate:1, rate:3, rate:5.
curl
curl -X POST "https://wa-api.geskap.com/v1/messages/interactive" \
-H "Authorization: Bearer $GESKAP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+237690000001",
"body": "Merci pour votre visite Awa. Comment était-ce ?",
"buttons": [
{ "id": "rate:1", "title": "Bof" },
{ "id": "rate:3", "title": "Bien" },
{ "id": "rate:5", "title": "Excellent" }
]
}'
Node.js
const res = await fetch("https://wa-api.geskap.com/v1/messages/interactive", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"to": "+237690000001",
"body": "Merci pour votre visite Awa. Comment était-ce ?",
"buttons": [
{ "id": "rate:1", "title": "Bof" },
{ "id": "rate:3", "title": "Bien" },
{ "id": "rate:5", "title": "Excellent" }
]
}),
});
console.log(res.status, await res.json());
PHP
$ch = curl_init("https://wa-api.geskap.com/v1/messages/interactive");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("GESKAP_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"to" => "+237690000001",
"body" => "Merci pour votre visite Awa. Comment était-ce ?",
"buttons" => [
["id" => "rate:1", "title" => "Bof"],
["id" => "rate:3", "title" => "Bien"],
["id" => "rate:5", "title" => "Excellent"],
],
]),
]);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $res;
Python
import os, requests
res = requests.request(
"POST",
"https://wa-api.geskap.com/v1/messages/interactive",
headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
json={
"to": "+237690000001",
"body": "Merci pour votre visite Awa. Comment était-ce ?",
"buttons": [
{"id": "rate:1", "title": "Bof"},
{"id": "rate:3", "title": "Bien"},
{"id": "rate:5", "title": "Excellent"},
],
},
timeout=15,
)
print(res.status_code, res.json())
Réception, identique dans les deux cas :
const m = /^rate:([1-5])$/.exec(data.button_id || "");
if (m) await db.saveRating(data.from, Number(m[1])); // la note est dans l'id, jamais dans le libellé
La signature et la lecture de button_id : voir Savoir quel bouton ou quelle ligne le client a touché. Pour une enquête complète avec commentaire, voir Enquête de satisfaction.
| Élément | Limite |
|---|---|
| Boutons par message | 3 maximum (donc pas 5 notes en boutons) |
| Lignes par liste | 10 au total : 5 notes tiennent largement |
| Titre d'un bouton | 20 caractères |
| Titre d'une ligne | 24 caractères |
Attention
Piège : il n'existe pas de composant « étoiles » : une note est un choix parmi des lignes ou des boutons, avec un titre que vous écrivez (« 4 · Bien »). Ne comptez pas sur des étoiles dessinées. N'utilisez pas d'émoji comme seule indication : mettez le chiffre.
Attention
Piège : un client peut aussi taper « 4 » à la main. Dans ce cas button_id vaut null et la note est dans text : acceptez les deux, validez que c'est un chiffre de 1 à 5, sinon renvoyez la liste.
Preuve — vérifié dans le code de l'API : api_schemas.py, public_api.py, webhooks.py ; appliqué par la démo WhatsApp : engine.