Envoyer une alerte avec un bouton d'action (« 10 minutes restantes, prolonger 1 h »)

Oui — dans les 24 h, un message interactif avec un bouton [Prolonger 1 h] ; hors des 24 h, un template à bouton de réponse rapide (approuvé par Meta). Dans les deux cas le clic revient dans button_id.

Envoyer une alerte avec un bouton d'action (« 10 minutes restantes, prolonger 1 h »)

Astuce
Oui — dans les 24 h, un message interactif avec un bouton [Prolonger 1 h] ; hors des 24 h, un template à bouton de réponse rapide (approuvé par Meta). Dans les deux cas le clic revient dans button_id.

Scénario

Un client a une session en cours (salle de jeu, location, parking, abonnement d'essai). Quand il reste 10 minutes, vous l'avertissez et lui proposez de prolonger d'un geste. S'il touche le bouton, votre serveur prolonge et confirme.

Deux cas, selon que le client vous a écrit il y a moins de 24 h ou non :

Oui, dans les deux cas, mais avec un outil différent. Le bouton-lien (ouvrir une page) n'existe pas en message libre ; pour un lien dans un bouton, voir Un lien unique par client dans un bouton.

Conversation

Vous    : Il vous reste 10 minutes de session.
          [ Prolonger 1 h ]  [ Terminer ]
Client  : (touche « Prolonger 1 h »)
Webhook : message.inbound  type=text  text="Prolonger 1 h"  button_id="session:extend:S789"
Vous    : Session prolongée d'1 h, jusqu'à 21:40. Merci !

Code

Dans les 24 h, message interactif :

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": "Il vous reste 10 minutes de session.",
  "buttons": [
    { "id": "session:extend:S789", "title": "Prolonger 1 h" },
    { "id": "session:end:S789", "title": "Terminer" }
  ]
}'

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": "Il vous reste 10 minutes de session.",
    "buttons": [
      { "id": "session:extend:S789", "title": "Prolonger 1 h" },
      { "id": "session:end:S789", "title": "Terminer" }
    ]
  }),
});
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" => "Il vous reste 10 minutes de session.",
    "buttons" => [
      ["id" => "session:extend:S789", "title" => "Prolonger 1 h"],
      ["id" => "session:end:S789", "title" => "Terminer"],
    ],
  ]),
]);
$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": "Il vous reste 10 minutes de session.",
        "buttons": [
            {"id": "session:extend:S789", "title": "Prolonger 1 h"},
            {"id": "session:end:S789", "title": "Terminer"},
        ],
    },
    timeout=15,
)
print(res.status_code, res.json())

Hors des 24 h, template à bouton de réponse rapide (créé et approuvé au préalable, voir Boutons de réponse rapide dans un 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": "alerte_session_fin",
    "language": "fr",
    "variables": ["10"]
  }
}'

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": "alerte_session_fin",
      "language": "fr",
      "variables": ["10"]
    }
  }),
});
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" => "alerte_session_fin",
      "language" => "fr",
      "variables" => ["10"],
    ],
  ]),
]);
$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": "alerte_session_fin",
            "language": "fr",
            "variables": ["10"],
        },
    },
    timeout=15,
)
print(res.status_code, res.json())

Choix du bon envoi côté serveur, puis réception du clic :

// Vous connaissez la date du dernier message reçu de ce client (webhook message.inbound)
const within24h = Date.now() - lastInboundAt < 24 * 3600 * 1000;
await (within24h ? sendInteractiveAlert(to, sessionId) : sendTemplateAlert(to, sessionId));

// Réception (voir « Savoir quel bouton… »)
if (data.button_id?.startsWith("session:extend:")) {
  const sessionId = data.button_id.split(":")[2];
  await db.extendSession(sessionId, { hours: 1 });  // relisez l'état : la session existe-t-elle encore ?
  await sendText(data.from, "Session prolongée d'1 h.");
}

Le clic sur le bouton du template arrive de la même façon (button_id = le libellé du bouton) : voir Savoir quel bouton ou quelle ligne le client a touché. Ce clic est un message du client : il rouvre la fenêtre de 24 h, et votre confirmation peut partir en texte libre.

Limites exactes

ÉlémentInteractif (dans les 24 h)Template (hors 24 h)
Nombre de boutons1 à 32 de réponse rapide au plus
Titre d'un bouton20 caractères25 caractères
Validation Metaaucuneobligatoire avant l'envoi
Texte1 024 caractères1 024 caractères
Attention
Piège : une alerte doit partir à la bonne minute : l'API n'a pas de minuteur. C'est votre planificateur qui déclenche l'envoi, et il doit décider interactif ou template selon la date du dernier message du client, sans quoi l'appel interactif échoue hors des 24 h.
Attention
Piège : un client peut toucher « Prolonger » après l'expiration de la session, ou deux fois. Au retour, relisez l'état chez vous (session expirée ? déjà prolongée ?) avant de prolonger, et ne prolongez qu'une fois par alerte. Si l'extension se paie, ne la confirmez qu'après l'encaissement : un clic n'est pas un paiement.

Preuve — vérifié dans le code de l'API : api_schemas.py, public_api.py, api_send.py, webhooks.py.