Demander une note de 1 à 5 au client

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.

Demander une note de 1 à 5 au client

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.

Scénario

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.

Conversation

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 !

Code

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.

Limites exactes

ÉlémentLimite
Boutons par message3 maximum (donc pas 5 notes en boutons)
Lignes par liste10 au total : 5 notes tiennent largement
Titre d'un bouton20 caractères
Titre d'une ligne24 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.