Postbacks Facebook Messenger expliqués : gérer les taps de boutons dans les webhooks
13 mai 2026
·
14 min de lecture
Dans ce guide : Ce qu'est un postback · Le flux des données · Les trois types de boutons qui génèrent des postbacks · Les schémas exacts des payloads webhook · Le piège de l'abonnement messaging_postbacks · Postback vs quick reply · Patrons de conception de payload · Postbacks de référence depuis les publicités · Système de routage en production · Le format normalisé SocialHook
Qu'est-ce qu'un postback Facebook Messenger ?
Un postback est l'événement webhook déclenché lorsqu'un utilisateur appuie sur un bouton configuré avec une chaîne payload dans Facebook Messenger. Le payload est une chaîne que vous définissez lors de la construction du bouton — elle voyage de votre serveur vers Meta puis vers le client de l'utilisateur, et revient à votre serveur lorsqu'on appuie dessus. C'est ainsi que Messenger indique à votre bot : « l'utilisateur a fait un choix délibéré, et voici lequel ».
Contrairement à un message texte (où l'utilisateur tape quelque chose d'imprévisible), un postback transporte exactement le payload que vous avez configuré — pas besoin de NLP, pas de correspondance approximative, pas de détection d'intention. L'utilisateur a tapé « Suivre ma commande » et votre serveur reçoit TRACK_ORDER. Déterministe, propre, fiable.
Le mécanisme de postback alimente trois des éléments interactifs les plus importants de Messenger :
Les boutons de postback dans les messages template (button template, carousel generic template)
Les éléments du menu persistant (l'icône hamburger en bas de chaque conversation)
Les entrées de référence (utilisateurs arrivant via des liens m.me ou des publicités Click-to-Messenger)
Le flux de données complet : du tap à l'événement webhook
🔘
Vous configurez
Bouton avec payload: "TRACK_ORDER"
👆
L'utilisateur appuie
Bouton dans l'UI Messenger
📡
Meta déclenche
POST vers votre URL webhook
⚡
Votre serveur
event.postback .payload === "TRACK_ORDER"
Le détail crucial dans ce flux : l'événement webhook déclenché par Meta est un événement postback — il arrive sous entry.messaging[].postback, et non sous entry.messaging[].message. C'est pourquoi de nombreux développeurs passent à côté : ils écrivent un gestionnaire de messages et s'étonnent que les taps de bouton n'arrivent jamais. Voir la section sur les abonnements ci-dessous pour comprendre pourquoi cela se produit et comment y remédier.
Les trois types de boutons qui génèrent des postbacks
Postback Button
Dans les templates
Apparaît dans les messages button template, generic template (carousel) ou media template. Reste visible dans la conversation après avoir été tapé. Maximum 3 boutons par button template, 3 par carte generic template. Libellé du bouton : 20 caractères max.
Le payload arrive à
event.postback.payload
Élément de menu persistant
Toujours visible
Défini via la Messenger Profile API une fois par Page — apparaît comme une icône de menu hamburger pour tous les utilisateurs. Structure imbriquée autorisée (2 niveaux). Les éléments de menu de type « postback » déclenchent des événements postback ; le type « web_url » ouvre une URL sans postback.
Le payload arrive à
event.postback.payload
Quick Reply
Disparaît après le tap
Apparaît sous forme de bulles défilant horizontalement. Disparaît après que l'utilisateur en a tapé une ou envoyé un autre message. Bien qu'il déclenche une chaîne « payload », les quick replies n'arrivent PAS dans des événements postback — ils arrivent dans des événements message. Voir la comparaison ci-dessous.
Le payload arrive à
event.message.quick_reply.payload
Schémas exacts des payloads webhook pour chaque type
Postback button et élément de menu persistant
Postback event — full raw webhook payload
{
"object": "page",
"entry": [{
"id": "PAGE_ID",
"messaging": [{
"sender": { "id": "12345678901234" }, // PSID of user who tapped"recipient": { "id": "PAGE_ID" },
"timestamp": 1747231892100,
"postback": { // ← THIS IS THE POSTBACK OBJECT (not .message)"mid": "m_abc123...", // message ID of the button message"title": "Track My Order",// the button label the user saw and tapped"payload": "TRACK_ORDER"// ← YOUR PAYLOAD — what you configured on the button
}
}]
}]
}
// Extraction: event.postback.payload === "TRACK_ORDER"// event.postback.title === "Track My Order" (the label — useful for logging)// event.sender.id === PSID of the user who tapped
Quick reply (PAS un postback — arrive dans les événements messaging)
Quick reply event — lives in .message, not .postback
{
"messaging": [{
"sender": { "id": "12345678901234" },
"timestamp": 1747231892100,
"message": { // ← note: .message, not .postback"mid": "m_def456...",
"text": "Yes, please!", // the quick reply title sent as a message text"quick_reply": {
"payload": "CONFIRM_YES"// ← YOUR PAYLOAD — same concept, different location
}
}
}]
}
// Extraction: event.message.quick_reply.payload === "CONFIRM_YES"// event.message.text still contains the quick reply title text// Subscription needed: messages (NOT messaging_postbacks)
Le piège de l'abonnement : pourquoi vos postbacks n'arrivent pas
⚠️
Vous devez vous abonner séparément à messaging_postbacks
C'est la raison n°1 pour laquelle les développeurs signalent « mes boutons ne fonctionnent pas » — ils se sont abonnés à messages mais pas à messaging_postbacks. Ce sont des abonnements aux champs webhook distincts. S'abonner à l'un n'inclut pas l'autre. Sans messaging_postbacks, votre endpoint POST ne recevra jamais d'événement postback, même si votre bouton est correctement configuré avec un payload.
✓ messages → messages texte, pièces jointes, quick replies
✓ messaging_postbacks → taps de bouton, menu persistant, références
✗ NON inclus automatiquement
Graph API (par programmation) : POST vers /PAGE_ID/subscribed_apps avec subscribed_fields=messages,messaging_postbacks,message_reads
Postback buttons vs quick replies : quand utiliser lequel
La distinction fondamentale dans votre gestionnaire de webhook : les événements postback arrivent à event.postback ; les payloads de quick reply arrivent à event.message.quick_reply. Votre routeur doit vérifier les deux emplacements.
Node.js — detect and extract all payload types
detectPayload.js
functionextractPayload(event) {
// 1. Standard postback button or persistent menu tapif (event.postback?.payload) {
return {
type: 'POSTBACK',
payload: event.postback.payload,
title: event.postback.title, // button label — useful for logging
};
}
// 2. Quick reply button tap (arrives in message event)if (event.message?.quick_reply?.payload) {
return {
type: 'QUICK_REPLY',
payload: event.message.quick_reply.payload,
title: event.message.text, // quick reply title sent as message text
};
}
// 3. Referral postback (user arrived via m.me link or ad)if (event.postback?.referral || event.referral) {
const ref = event.postback?.referral || event.referral;
return {
type: 'REFERRAL',
payload: event.postback?.payload || null,
ref: ref.ref, // your tracking parameter
source: ref.source, // 'SHORTLINK' | 'ADS' | 'CUSTOMER_CHAT_PLUGIN' | etc
};
}
// 4. Regular text message — no payloadif (event.message?.text) {
return {
type: 'TEXT',
payload: null,
text: event.message.text,
};
}
return { type: 'UNKNOWN', payload: null };
}
Patrons de conception de payload : bons vs mauvais
La chaîne de payload vous appartient — Facebook la traite comme une chaîne opaque. La façon dont vous concevez vos payloads détermine la maintenabilité et la facilité de débogage de la logique de votre bot à grande échelle. Voici les patrons qui fonctionnent et ceux qui causent des problèmes :
Facile à router avec startsWith() ou switch. Le préfixe indique le flux, le suffixe indique le choix. Lisible dans les logs. Suffisamment court pour rester bien en dessous de la limite de 1 000 caractères.
JSON.stringify() l'objet, JSON.parse() à la réception. À utiliser uniquement lorsque vous devez transmettre un contexte qui ne peut être déduit de l'état de la conversation. Restez compact — chaque caractère compte dans les 1 000.
✗ Mauvais — mots uniques opaques
Payloads en collision, ambigus
YES NO NEXT OK BACK
Ces valeurs entrent en collision entre les flux. « YES » à quoi ? Dans quel état de conversation ? Si vous avez deux button templates différents utilisant tous deux « YES », votre routeur ne peut pas les distinguer sans vérifier l'état de la conversation à chaque fois.
✗ Mauvais — texte vide ou visible par l'utilisateur
Payloads non lisibles par machine
"Yes, please!" "Track my order" ""
Les chaînes de payload vides amènent Facebook à rejeter la configuration du bouton. Utiliser comme payload du texte visible par l'utilisateur casse tout lorsque vous modifiez le libellé du bouton sans mettre à jour votre routeur. Les payloads doivent être des identifiants machine, pas des chaînes d'affichage.
Versionnez les payloads de votre menu persistant. Le menu persistant est défini globalement pour tous les utilisateurs de votre Page. Si vous ajoutez un élément de menu qui modifie une chaîne de payload, les utilisateurs existants qui n'ont pas encore ouvert Messenger obtiendront le nouveau menu. Utilisez des suffixes de version comme MENU_SUPPORT_V2 pour que votre routeur gère à la fois les anciens et les nouveaux payloads pendant les transitions. Ne réutilisez jamais une chaîne de payload pour une action différente.
Postbacks de référence : tracker les points d'entrée des campagnes
Lorsqu'un utilisateur clique sur un lien m.me avec un paramètre ref — comme m.me/yourpage?ref=EMAIL_CAMPAIGN_MAY — ou arrive via une publicité Click-to-Messenger, Facebook déclenche un événement de référence. C'est ainsi que vous suivez quelle campagne, publicité ou point d'entrée a amené un utilisateur dans Messenger.
Les événements de référence ont deux formes selon que l'utilisateur démarre une nouvelle conversation ou revient à une conversation existante :
Referral postback payloads — both forms
// Form 1: New conversation — arrives as a standalone referral event// (user has never messaged your Page before, or is starting fresh)
{
"referral": {
"ref": "EMAIL_CAMPAIGN_MAY", // your ?ref= parameter"source": "SHORTLINK", // 'SHORTLINK' | 'ADS' | 'CUSTOMER_CHAT_PLUGIN'"type": "OPEN_THREAD"// always "OPEN_THREAD" for user-initiated
}
// Note: no postback.payload — this is a pure referral with no button
}
// Form 2: Button click with referral context (e.g. persistent menu from ad landing)// Arrives as a postback event with BOTH payload AND referral
{
"postback": {
"title": "Get Started",
"payload": "GET_STARTED",
"referral": {
"ref": "AD_SUMMER_SALE",
"source": "ADS",
"type": "OPEN_THREAD"
}
}
// postback.payload = the button action// postback.referral.ref = the campaign tracking string
}
Pour recevoir les événements de référence, abonnez-vous à messaging_referrals. C'est un troisième abonnement webhook distinct de messages et messaging_postbacks. Sans lui, les événements de référence de la Form 1 (démarrages à froid de nouvelles conversations) n'arrivent jamais. La Form 2 (postback + référence) arrive avec un abonnement à messaging_postbacks. Abonnez-vous aux trois pour une couverture complète.
Système de routage en production : architecture de gestionnaires structurée
Un switch sur le payload fonctionne pour 5 boutons. À 50 boutons répartis sur 10 flux, cela devient ingérable. Voici le patron de production : un registre de routage qui mappe les préfixes de payload vers des modules de gestionnaires, avec prise en charge des payloads JSON.
Lorsque vous recevez des événements Messenger via SocialHook, les postbacks sont pré-extraits et livrés dans le même format normalisé que tous les autres types d'événements. L'imbrication brute entry[0].messaging[0].postback est déjà déballée :
SocialHook normalized postback event
// Postback button tap:
{
"platform": "facebook",
"event": "postback",
"from": "12345678901234", // PSID"postback": {
"payload": "TRACK_ORDER", // your payload — ready to route"title": "Track My Order"// button label
},
"signature_verified": true
}
// Quick reply payload:
{
"platform": "facebook",
"event": "message.received",
"from": "12345678901234",
"message": {
"type": "quick_reply",
"payload": "CONFIRM_YES", // extracted from message.quick_reply.payload"body": "Yes, please!"// the quick reply title text
},
"signature_verified": true
}
// Your handler:
app.post('/webhook', async (req, res) => {
res.sendStatus(200);
const { event, from, postback, message } = req.body;
if (event === 'postback') awaitroutePostback(from, postback.payload);
if (message?.type === 'quick_reply') awaitroutePostback(from, message.payload);
});
FAQ
Questions fréquentes
Qu'est-ce qu'un postback Facebook Messenger ?
Un postback est l'événement webhook déclenché lorsqu'un utilisateur appuie sur un Postback Button ou un élément du menu persistant. Vous configurez une chaîne payload sur le bouton — lorsqu'on appuie dessus, Facebook envoie cette chaîne exacte à votre webhook à event.postback.payload. C'est ainsi que votre bot reçoit des signaux d'intention structurés depuis les taps de bouton de l'utilisateur, sans aucun NLP ni analyse de texte.
Pourquoi mes postbacks Messenger n'arrivent-ils pas à mon webhook ?
Cause la plus probable : vous vous êtes abonné à messages mais pas à messaging_postbacks. Ce sont des abonnements distincts. Solution : Messenger Settings → Webhooks → Edit Subscriptions → cochez messaging_postbacks. Deuxième vérification : votre bouton est de type: 'postback' (et non type: 'web_url'). Troisième vérification : le champ payload de votre bouton n'est pas vide (les payloads vides provoquent un rejet silencieux).
Quelle est la différence entre un postback et un quick reply dans Messenger ?
Les deux délivrent une chaîne de payload lors du tap, mais diffèrent sur trois points : (1) Emplacement dans le webhook : postback → event.postback.payload ; quick reply → event.message.quick_reply.payload. (2) Apparence : les boutons postback persistent dans la conversation ; les quick replies disparaissent après un tap. (3) Abonnement : les postbacks nécessitent messaging_postbacks ; les quick replies arrivent avec messages.
Puis-je utiliser du JSON comme payload de postback Messenger ?
Oui — JSON.stringify() un objet et utilisez la chaîne résultante comme payload. À la réception, JSON.parse() pour le récupérer. Facebook traite le payload comme une chaîne opaque jusqu'à 1 000 caractères. Utilisez des payloads JSON lorsque vous devez transmettre un contexte structuré (productId, quantité, état du flux) qui ne peut pas être déduit du seul état de conversation. Utilisez du JSON compact : supprimez les espaces avec JSON.stringify(obj) (sans argument d'espace).
Comment savoir quelle campagne a amené un utilisateur à mon bot Messenger ?
Utilisez les postbacks de référence. Ajoutez un paramètre ?ref=YOUR_CAMPAIGN_ID à votre lien m.me (par exemple m.me/yourpage?ref=EMAIL_MAY). Lorsque l'utilisateur ouvre Messenger, un événement de référence est déclenché avec votre chaîne ref à event.referral.ref. Abonnez-vous à messaging_referrals pour recevoir les événements de référence à froid. Si l'utilisateur appuie sur un bouton après son arrivée, les données de référence apparaissent à côté du postback dans event.postback.referral.ref.
Comment configurer un menu persistant Messenger ?
POST une fois vers graph.facebook.com/v21.0/me/messenger_profile avec votre Page Access Token et un tableau persistent_menu. Chaque élément a un type (postback ou web_url), un title, et soit un payload (postback) soit une url (web_url). Les modifications s'appliquent globalement à tous les utilisateurs. Vous n'avez besoin d'appeler cette API que lors de la mise à jour du menu — elle persiste jusqu'à ce que vous la changiez. Les événements postback issus des éléments de menu arrivent à l'identique des postbacks de boutons de template.
Connectez votre Page Facebook à SocialHook. Chaque postback arrive à votre gestionnaire avec le payload déjà extrait — pas d'analyse de webhook brut, pas de débogage d'abonnement, pas de boilerplate HMAC. Juste event.postback.payload exactement quand vous en avez besoin.
Arrêtez de gérer les API Meta. Commencez à construire.
Connectez votre premier compte Facebook, Instagram ou WhatsApp en moins de 2 minutes. Votre webhook reçoit son premier payload avant que votre café refroidisse.