Mettre des boutons de réponse rapide dans un template (hors 24 h)

Oui : deux boutons quick_reply au maximum dans un template approuvé par Meta ; le clic revient en message.inbound avec le libellé touché, et rouvre la fenêtre de 24 h.

Mettre des boutons de réponse rapide dans un template (hors 24 h)

Astuce
Oui : deux boutons quick_reply au maximum dans un template approuvé par Meta ; le clic revient en message.inbound avec le libellé touché, et rouvre la fenêtre de 24 h.

Scénario

Vous notifiez un client hors des 24 h (livraison prévue demain, offre, enquête) et vous voulez qu'il réponde d'un clic : « Oui » ou « Non », au lieu de taper.

Oui, un template peut porter des boutons de réponse rapide. C'est la version « hors 24 h » des boutons sans template, avec deux différences : le template doit être approuvé par Meta avant l'envoi, et il y a 2 boutons au maximum (3 sans template).

Conversation

Vous    : POST /v1/messages  to=+237690000001  variables=["Awa", "demain entre 14 h et 16 h"]
Awa     : « Bonjour Awa, votre livraison est prévue demain entre 14 h et 16 h. Serez-vous présente ? »
          [ Oui ]  [ Non, reporter ]
Awa     : (touche « Non, reporter »)
Webhook : message.inbound  type=text  text="Non, reporter"

Code

  1. Créez le template avec des boutons "kind": "quick_reply" (sans url) :

curl

curl -X POST "https://wa-api.geskap.com/v1/templates" \
  -H "Authorization: Bearer $GESKAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "livraison_demain_presence",
  "language": "fr",
  "category": "UTILITY",
  "body_text": "Bonjour {{1}}, votre livraison est prévue {{2}}. Serez-vous présente ?",
  "example_values": ["Awa", "demain entre 14 h et 16 h"],
  "buttons": [
    { "kind": "quick_reply", "text": "Oui" },
    { "kind": "quick_reply", "text": "Non, reporter" }
  ]
}'

Node.js

const res = await fetch("https://wa-api.geskap.com/v1/templates", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "livraison_demain_presence",
    "language": "fr",
    "category": "UTILITY",
    "body_text": "Bonjour {{1}}, votre livraison est prévue {{2}}. Serez-vous présente ?",
    "example_values": ["Awa", "demain entre 14 h et 16 h"],
    "buttons": [
      { "kind": "quick_reply", "text": "Oui" },
      { "kind": "quick_reply", "text": "Non, reporter" }
    ]
  }),
});
console.log(res.status, await res.json());

PHP

$ch = curl_init("https://wa-api.geskap.com/v1/templates");
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([
    "name" => "livraison_demain_presence",
    "language" => "fr",
    "category" => "UTILITY",
    "body_text" => "Bonjour {{1}}, votre livraison est prévue {{2}}. Serez-vous présente ?",
    "example_values" => ["Awa", "demain entre 14 h et 16 h"],
    "buttons" => [
      ["kind" => "quick_reply", "text" => "Oui"],
      ["kind" => "quick_reply", "text" => "Non, reporter"],
    ],
  ]),
]);
$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/templates",
    headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
    json={
        "name": "livraison_demain_presence",
        "language": "fr",
        "category": "UTILITY",
        "body_text": "Bonjour {{1}}, votre livraison est prévue {{2}}. Serez-vous présente ?",
        "example_values": ["Awa", "demain entre 14 h et 16 h"],
        "buttons": [
            {"kind": "quick_reply", "text": "Oui"},
            {"kind": "quick_reply", "text": "Non, reporter"},
        ],
    },
    timeout=15,
)
print(res.status_code, res.json())
  1. Une fois APPROVED, envoyez-le comme n'importe quel template :

curl

curl -X POST "https://wa-api.geskap.com/v1/messages" \
  -H "Authorization: Bearer $GESKAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+237690000001",
  "template": {
    "name": "livraison_demain_presence",
    "language": "fr",
    "variables": ["Awa", "demain entre 14 h et 16 h"]
  },
  "idempotency_key": "livraison-CMD-1042"
}'

Node.js

const res = await fetch("https://wa-api.geskap.com/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "to": "+237690000001",
    "template": {
      "name": "livraison_demain_presence",
      "language": "fr",
      "variables": ["Awa", "demain entre 14 h et 16 h"]
    },
    "idempotency_key": "livraison-CMD-1042"
  }),
});
console.log(res.status, await res.json());

PHP

$ch = curl_init("https://wa-api.geskap.com/v1/messages");
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",
    "template" => [
      "name" => "livraison_demain_presence",
      "language" => "fr",
      "variables" => ["Awa", "demain entre 14 h et 16 h"],
    ],
    "idempotency_key" => "livraison-CMD-1042",
  ]),
]);
$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",
    headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
    json={
        "to": "+237690000001",
        "template": {
            "name": "livraison_demain_presence",
            "language": "fr",
            "variables": ["Awa", "demain entre 14 h et 16 h"],
        },
        "idempotency_key": "livraison-CMD-1042",
    },
    timeout=15,
)
print(res.status_code, res.json())

Règles exactes

ÉlémentRègle
Nombre de boutons2 au maximum par template
Libellé (text)25 caractères au plus
Typequick_reply : pas de lien (url est ignoré)
Mélangene mélangez pas boutons quick_reply et boutons url dans un même template

Le clic est un message entrant type: "text" ; son text est le libellé touché. Voir Savoir quel bouton le client a touché.

Attention
Piège : contrairement aux boutons sans template, vous ne choisissez pas d'id : l'envoi par l'API ne transmet aucun identifiant personnalisé. Aiguillez sur le libellé (text) et rattachez la réponse au dernier envoi fait à ce numéro from. Deux libellés identiques dans deux templates ne se distinguent pas par leur text : donnez-leur des libellés différents.
Attention
Piège : le libellé fait partie du template approuvé. Pour le changer, il faut soumettre une nouvelle version à Meta. Choisissez des libellés courts et stables (« Oui », « Non, reporter »).
Attention
Piège : après le clic, le client vous a écrit : la fenêtre de 24 h est ouverte, vous pouvez répondre en texte libre ou avec des boutons sans template. Pour le parcours complet d'un rappel de rendez-vous : Rappel la veille.

Un bouton qui ouvre une page web est un autre type de bouton, qui peut même porter un lien différent par client : voir Lien variable dans un bouton. Premier envoi, statuts et erreurs : Écrire à un client qui ne vous a jamais écrit.

Preuve — vérifié dans le code de l'API : api_schemas.py, templates.py, meta_webhooks.py, README.md.