ITSkillsCenter
E-commerce

Créer et faire approuver des templates WhatsApp Business en 2026

19 دقائق للقراءة

📍 Article principal de la série : WhatsApp Cloud API en 2026 : architecture, webhooks, templates et intégrations.

Hors de la fenêtre de conversation de 24 heures ouverte par un message entrant utilisateur, WhatsApp Cloud API n’autorise plus le moindre texte libre vers un client. Toute reprise de contact, toute notification de livraison, toute confirmation de commande, toute relance de panier doit obligatoirement passer par un template approuvé par Meta. Cette règle, inflexible depuis la refonte tarifaire de 2024 et durcie en 2025, fait des templates le goulot d’étranglement de tout projet WhatsApp sérieux. Un template mal catégorisé est rejeté, un template trop promotionnel est pausé, un template mal libellé fait grimper la note mensuelle de plusieurs centaines d’euros. Ce tutoriel guide pas à pas un développeur ou un intégrateur dans la création, la soumission et la maintenance de templates Marketing, Utility et Authentication, avec les pièges concrets observés en production.

Prérequis

Avant de toucher à la console Meta ou à un appel API, trois éléments doivent être en place. Premièrement, un WhatsApp Business Account (WABA) actif, c’est-à-dire un compte créé dans Meta Business Manager auquel un numéro WhatsApp Business a été rattaché et vérifié. Deuxièmement, des droits suffisants sur ce WABA : rôle Administrateur ou au minimum Gestionnaire de message templates dans Business Manager, sinon les boutons d’édition des templates restent grisés sans message d’erreur clair. Troisièmement, pour la voie API, un jeton d’accès permanent attaché à un utilisateur système et portant le scope whatsapp_business_management. Le jeton court provenant de la console développeur expire en 24 heures et ne convient pas à une intégration en production.

Notez aussi votre identifiant WABA_ID : il s’affiche dans Business Manager → Comptes → WhatsApp Accounts → onglet Paramètres. C’est cet identifiant numérique (et non l’identifiant du numéro de téléphone) qui sert d’ancre à toutes les requêtes touchant aux templates.

Comprendre les quatre catégories : Marketing, Utility, Authentication, Service

Meta classe chaque conversation WhatsApp Business dans l’une des quatre catégories tarifées et réglementées suivantes. Choisir la mauvaise au moment de soumettre un template est la cause numéro un de rejet et de surfacturation.

  • Marketing — toute promotion, offre, lancement, relance d’inactivité, invitation à découvrir un produit. C’est la catégorie la plus chère et la plus surveillée par la modération de Meta.
  • Utility — confirmation d’une action initiée par l’utilisateur : confirmation de commande, mise à jour de statut, reçu, alerte de livraison, rappel de rendez-vous. Tarif intermédiaire, modération beaucoup plus permissive si le template reste descriptif et factuel.
  • Authentication — exclusivement pour les codes à usage unique (OTP) destinés à valider une connexion ou une opération sensible. Tarif spécifique le plus bas de la grille, mais format strictement contraint par Meta.
  • Service — conversations initiées par l’utilisateur dans la fenêtre de 24 heures. Depuis le 1er novembre 2024, les messages Service ne sont plus facturés par Meta tant qu’ils restent dans la fenêtre ouverte. Ils n’utilisent pas de template puisque le canal est libre.

Retenez ce point souvent mal compris : Marketing, Utility et Authentication sont des catégories de template, donc concernent les messages que vous initiez hors fenêtre. Service n’est pas une catégorie de template, c’est un statut de conversation. Vous ne créerez jamais de template Service.

Étape 1 — Choisir la bonne catégorie pour éviter le rejet

Avant d’écrire la première ligne de votre template, posez-vous une question : quel est l’événement déclencheur côté utilisateur ? Si l’utilisateur a passé une commande, ouvert un ticket, demandé un rendez-vous, le message qui suit est presque toujours Utility. Si vous décidez seul, sans action préalable du client, d’envoyer une offre ou de relancer un panier abandonné, c’est Marketing. Si le message contient un code à six chiffres ou un lien magique de connexion, c’est Authentication.

Le piège classique consiste à déguiser un message Marketing en Utility pour profiter du tarif moins élevé. Meta dispose depuis 2024 d’un classifieur automatique qui requalifie d’office un template soumis en Utility mais dont le contenu pousse à l’achat. Concrètement, si votre Utility contient des mots comme « offre exceptionnelle », « 30 % de remise », « nouvelle collection », vous serez requalifié en Marketing à la facturation, voire purement rejeté avec le motif CATEGORY_MISMATCH.

Pour une boutique de vêtements pudiques qui veut envoyer la confirmation d’une commande, le template doit s’en tenir à : numéro de commande, articles, montant, date de livraison estimée. Pas un mot sur la nouvelle collection. La promotion partira séparément, dans un template Marketing assumé.

Étape 2 — Créer un template Utility via Meta Business Suite

Pour un premier template, l’interface graphique de Meta Business Suite est plus rapide que l’API et détecte certaines erreurs de format en temps réel. Connectez-vous à business.facebook.com, ouvrez le compte WABA, puis cliquez sur WhatsApp Manager dans le menu de gauche. Sélectionnez l’onglet Modèles de messages et cliquez sur Créer un modèle.

Le formulaire vous demande successivement la catégorie (choisissez Utility), un nom de modèle (en minuscules, sans espace, par exemple order_confirmation_v1) et la langue principale. Un template par couple (nom, langue). Si vous comptez répondre en français et en arabe, créez deux entrées séparées avec le même nom mais des codes langue différents (fr et ar).

Vient ensuite la composition du template, structurée en quatre blocs optionnels : en-tête (texte court, image, vidéo ou document PDF), corps (le texte principal, jusqu’à 1024 caractères), pied de page (texte court informatif, 60 caractères) et boutons (quick-reply ou call-to-action, voir étape 4). Le corps est le seul bloc obligatoire.

Pour notre boutique de vêtements pudiques, un corps Utility valide ressemble à :

Bonjour {{1}}, votre commande #{{2}} d'un montant de {{3}} a bien été enregistrée.
Livraison estimée le {{4}} à l'adresse renseignée.
Vous recevrez un nouveau message dès que votre colis sera expédié.

Les marqueurs {{1}} à {{4}} sont des variables que vous remplirez à l’envoi. Meta exige depuis 2023 un exemple de valeur pour chaque variable, à fournir dans le formulaire juste sous le corps. Sans cet exemple, le bouton Envoyer pour révision reste désactivé. Donnez des valeurs réalistes (par exemple Aïssatou Diop, CMD-2026-0413, 27 500 XOF, 5 mai 2026) — l’examinateur humain s’en sert pour juger la cohérence du template.

Une fois le formulaire rempli, cliquez sur Soumettre. Le template apparaît immédiatement dans la liste avec le statut PENDING.

Étape 3 — Créer un template via API : exemple Authentication avec OTP

Pour les équipes qui versionnent leurs templates dans un dépôt Git ou qui en gèrent plusieurs dizaines, l’API Business Management est indispensable. L’endpoint canonique est :

POST https://graph.facebook.com/v23.0/{WABA_ID}/message_templates

L’appel suivant crée un template Authentication conforme aux contraintes très strictes que Meta impose à cette catégorie depuis avril 2024 : le corps est figé, vous ne maîtrisez que l’application name et l’expiration. Tout texte personnalisé dans un Authentication est désormais refusé.

curl -X POST \
  "https://graph.facebook.com/v23.0/123456789012345/message_templates" \
  -H "Authorization: Bearer EAAG...PERMANENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "halal_delivery_otp",
    "language": "fr",
    "category": "AUTHENTICATION",
    "components": [
      {
        "type": "BODY",
        "add_security_recommendation": true
      },
      {
        "type": "FOOTER",
        "code_expiration_minutes": 10
      },
      {
        "type": "BUTTONS",
        "buttons": [
          {
            "type": "OTP",
            "otp_type": "COPY_CODE",
            "text": "Copier le code"
          }
        ]
      }
    ]
  }'

Si la création réussit, l’API renvoie un objet contenant l’identifiant interne du template et son statut :

{
  "id": "987654321098765",
  "status": "PENDING",
  "category": "AUTHENTICATION"
}

Le signal de réussite à attendre est le couple id non vide et status: "PENDING". Si la réponse contient un champ error avec un sous-code 2388023 ou similaire, c’est généralement que add_security_recommendation ou code_expiration_minutes n’a pas été placé dans le bon component. La règle : recommandation de sécurité dans BODY, expiration dans FOOTER, bouton OTP dans BUTTONS — pas l’inverse.

Pour une plateforme de livraison alimentaire halal qui envoie un OTP de validation à la connexion, le rendu côté client affiche automatiquement un texte standardisé multilingue géré par WhatsApp lui-même, suivi du code et du bouton Copier le code. Vous n’avez plus besoin de rédiger « Voici votre code de validation : 123456 » — Meta gère ce libellé.

Étape 4 — Ajouter des variables, boutons quick-reply et call-to-action

Les variables se déclarent avec la syntaxe {{n}}n est un entier commençant à 1, sans saut de numérotation et sans réutilisation. Elles sont autorisées dans l’en-tête texte, le corps et le label des boutons URL dynamiques. Le pied de page reste statique. Pour chaque variable déclarée, Meta exige une valeur d’exemple lors de la soumission, faute de quoi le template part en REJECTED avec motif INVALID_FORMAT.

Les boutons se divisent en deux familles mutuellement exclusives. Les quick-reply permettent au client de répondre d’un tap (par exemple « Oui », « Non », « Annuler ma commande ») ; vous en autorisez jusqu’à trois par template. Les call-to-action ouvrent une URL ou composent un numéro ; vous en autorisez jusqu’à deux, dont un seul de type URL et un seul de type téléphone. Vous ne pouvez pas mélanger quick-reply et call-to-action dans un même template.

Voici un payload API qui crée un template Marketing avec deux boutons call-to-action pour une banque islamique annonçant une nouvelle offre de financement participatif :

{
  "name": "musharakah_offer_q2_2026",
  "language": "fr",
  "category": "MARKETING",
  "components": [
    {
      "type": "HEADER",
      "format": "TEXT",
      "text": "Nouvelle offre de financement participatif"
    },
    {
      "type": "BODY",
      "text": "Bonjour {{1}}, notre offre de financement participatif pour vos projets professionnels est disponible. Découvrez les conditions et déposez votre dossier en ligne.",
      "example": {
        "body_text": [["Aïssatou"]]
      }
    },
    {
      "type": "BUTTONS",
      "buttons": [
        {
          "type": "URL",
          "text": "Voir l'offre",
          "url": "https://exemple.test/financement"
        },
        {
          "type": "PHONE_NUMBER",
          "text": "Appeler un conseiller",
          "phone_number": "+221338000000"
        }
      ]
    }
  ]
}

Si l’appel réussit, vous recevez à nouveau un objet avec status: "PENDING". Si l’URL ou le numéro est mal formé, l’API répond immédiatement avec une erreur 400 et n’enregistre rien — le template n’apparaît pas dans la liste de Business Manager. C’est un avantage de la voie API : la validation syntaxique est synchrone, vous n’attendez pas 24 heures pour découvrir une typo.

Étape 5 — Soumettre à Meta et comprendre le délai d’approbation

Que vous passiez par l’interface ou par l’API, la soumission place le template en file d’attente avec le statut PENDING. Meta annonce officiellement un délai d’examen pouvant aller jusqu’à 24 heures, mais dans la pratique observée en 2026 deux scénarios coexistent.

Le scénario rapide concerne les Utility et Authentication simples, sans variable exotique, sur un WABA dont l’historique de modération est propre : la décision tombe en quelques minutes via une revue automatique. Le scénario lent concerne les Marketing, les templates avec image en en-tête, ou les WABA récemment créés : la file passe alors par un examinateur humain et l’attente peut atteindre 24 à 48 heures, plus rarement davantage en cas de pic de soumissions à l’approche de Black Friday ou du Ramadan.

Pour suivre le statut sans rafraîchir Business Suite, interrogez l’API :

curl -G "https://graph.facebook.com/v23.0/123456789012345/message_templates" \
  -H "Authorization: Bearer EAAG...PERMANENT_TOKEN" \
  --data-urlencode "fields=name,status,category,rejected_reason"

La réponse liste tous vos templates et leurs statuts. Les valeurs possibles, documentées par Meta, sont PENDING (en cours d’examen), APPROVED (utilisable immédiatement), REJECTED (refusé, voir rejected_reason), DISABLED (désactivé suite à une violation après approbation) et PAUSED (mis en pause à cause d’un taux de plainte élevé).

En production, branchez ce contrôle sur un cron toutes les 15 minutes pendant les soumissions en cours, puis désactivez-le dès que tout est APPROVED. Vous pouvez aussi vous abonner à l’événement webhook message_template_status_update pour être notifié en push, ce qui évite le polling.

Étape 6 — Gérer les rejets : motifs fréquents et comment corriger

Un rejet n’est jamais définitif — vous pouvez modifier le template et le re-soumettre autant de fois que nécessaire, sans pénalité tant que vous restez sous une centaine de soumissions par jour. Le champ rejected_reason renvoyé par l’API donne le motif principal, mais reste assez laconique. Voici les motifs réellement vus en production et la correction qui marche.

INVALID_FORMAT — généralement lié à une variable mal numérotée (saut entre {{1}} et {{3}}), un exemple manquant pour une variable, ou un caractère interdit dans le nom du template (majuscule, espace, accent). La correction est mécanique : renumérotez les variables sans trou, fournissez un exemple pour chacune, renommez le template en snake_case minuscule.

NO_BUTTON_TEXT — vous avez déclaré un bouton sans label, ou avec un label vide. Pour un bouton URL ou téléphone, le champ text est obligatoire et limité à 25 caractères. Vérifiez aussi qu’aucun bouton n’à un label en double dans le même template.

CATEGORY_MISMATCH — Meta estime que le contenu ne correspond pas à la catégorie soumise. Le cas typique est un Utility qui contient des termes promotionnels. Soit vous gommez le ton commercial pour rester en Utility, soit vous re-soumettez en Marketing en assumant le tarif plus élevé.

REJECTED_GENERIC ou NON_COMPLIANT — motif fourre-tout qui couvre plusieurs cas : promesses irréalistes (« devenez riche »), contenu trompeur, formulation jugée intrusive, mentions de produits non autorisés sur la plateforme. Demandez-vous si un humain raisonnable trouverait le message acceptable. Si la cause vous échappe, ouvrez un ticket via Business Suite — le support spécialisé WhatsApp répond en général sous 48 heures avec un motif détaillé.

Une astuce qui fait gagner des heures : créez d’abord une version v1 minimaliste qui passe à coup sûr, puis itérez par versions v2, v3 en ajoutant progressivement boutons et variables. Vous identifiez ainsi exactement quel ajout déclenche le rejet.

Étape 7 — Envoyer un template approuvé : exemple curl + Node.js

Une fois votre template en APPROVED, l’envoi s’effectue contre l’endpoint messages du numéro de téléphone, et non plus contre celui du WABA. L’identifiant à utiliser est le PHONE_NUMBER_ID visible dans la console développeur de votre app. La requête en curl ressemble à ceci :

curl -X POST \
  "https://graph.facebook.com/v23.0/PHONE_NUMBER_ID/messages" \
  -H "Authorization: Bearer EAAG...PERMANENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "221770000000",
    "type": "template",
    "template": {
      "name": "order_confirmation_v1",
      "language": { "code": "fr" },
      "components": [
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "Aïssatou Diop" },
            { "type": "text", "text": "CMD-2026-0413" },
            { "type": "text", "text": "27 500 XOF" },
            { "type": "text", "text": "5 mai 2026" }
          ]
        }
      ]
    }
  }'

L’API renvoie un objet contenant un messages[0].id commençant par wamid.. Cet identifiant est votre référence pour suivre le cycle de vie du message côté webhook. Si vous recevez à la place une erreur de type (#132012) Parameter format does not match format in the template, c’est que le nombre de paramètres envoyés ne correspond pas exactement au nombre de variables déclarées dans le template approuvé.

Côté Node.js, le même envoi via fetch natif (Node 18+) reste lisible et tient en une fonction :

async function sendOrderConfirmation(toMsisdn, name, orderId, amount, date) {
  const url = `https://graph.facebook.com/v23.0/${process.env.PHONE_NUMBER_ID}/messages`;
  const body = {
    messaging_product: "whatsapp",
    to: toMsisdn,
    type: "template",
    template: {
      name: "order_confirmation_v1",
      language: { code: "fr" },
      components: [{
        type: "body",
        parameters: [
          { type: "text", text: name },
          { type: "text", text: orderId },
          { type: "text", text: amount },
          { type: "text", text: date }
        ]
      }]
    }
  };

  const res = await fetch(url, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.WA_TOKEN}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });

  const data = await res.json();
  if (!res.ok) throw new Error(`WA send failed: ${JSON.stringify(data)}`);
  return data.messages[0].id;
}

La fonction renvoie le wamid en cas de succès, ce que vous stockerez en base pour la corrélation. Pensez à mettre cet appel derrière une file d’attente (BullMQ, Redis, ou un simple worker Postgres) : à 80 messages par seconde de plafond par défaut sur un numéro standard, un envoi en masse synchrone vous expose à des erreurs (#80007) Rate limit hit.

Étape 8 — Vérification : statut de livraison via webhook

L’envoi réussi ne garantit pas la livraison. Pour confirmer qu’un template approuvé a effectivement atteint le téléphone du client, vous devez écouter l’événement messages.statuses que Meta pousse vers l’URL webhook configurée sur votre app. Chaque statut intermédiaire arrive sous la forme suivante :

{
  "entry": [{
    "changes": [{
      "value": {
        "statuses": [{
          "id": "wamid.HBgL...",
          "status": "delivered",
          "timestamp": "1746450000",
          "recipient_id": "221770000000",
          "conversation": {
            "id": "abc123",
            "origin": { "type": "utility" }
          },
          "pricing": {
            "billable": true,
            "category": "utility",
            "pricing_model": "CBP"
          }
        }]
      }
    }]
  }]
}

Les statuts successifs à intercepter sont sent (Meta a accepté), delivered (le téléphone a accusé réception), read (le client a ouvert la conversation, sous réserve qu’il n’ait pas désactivé les confirmations de lecture) et failed (échec, avec un sous-objet errors qui détaille la cause). Stockez chaque mise à jour avec le wamid en clé : c’est votre seule source fiable pour le pilotage de campagne.

Le bloc pricing est précieux : il vous indique a posteriori dans quelle catégorie Meta a réellement facturé la conversation. Si vous avez soumis un Utility et que vous voyez "category": "marketing" ici, c’est que la requalification automatique a frappé. Conservez cet historique pour piloter votre coût mensuel et arbitrer entre Utility plus discrets et Marketing assumés.

Erreurs fréquentes

Code / motif Cause typique Correction
NO_BUTTON_TEXT Bouton déclaré sans text ou label vide Renseigner un libellé court (≤ 25 caractères) sur chaque bouton
INVALID_FORMAT Variables non séquentielles, exemples manquants, nom invalide Renuméroter, fournir un exemple par variable, passer le nom en snake_case
CATEGORY_MISMATCH Termes promotionnels dans un Utility Soit neutraliser le ton, soit re-soumettre en Marketing
REJECTED_GENERIC Contenu jugé trompeur, intrusif ou interdit Reformuler factuellement, ouvrir un ticket support pour précision
(#132012) Parameter format does not match Nombre de paramètres envoyés ≠ variables du template Aligner exactement le tableau parameters sur le template approuvé
(#131056) Pair rate limit hit Trop d’envois vers un même numéro en peu de temps Espacer les envois ou activer une file de débit
PAUSED (statut) Taux de plaintes ou de blocages élevé sur un template Réviser le ciblage, attendre la fin de la période de pause (24h, 3 jours, 30 jours selon récidive)

Bonnes pratiques pour passer la modération

Trois habitudes réduisent fortement le taux de rejet. Premièrement, écrivez pour un humain pressé. Une phrase courte par information, pas de formules creuses, le nom du destinataire en première variable, l’action attendue clairement énoncée. Les modérateurs Meta passent quelques secondes par template et tranchent sur l’impression générale.

Deuxièmement, alignez le texte avec votre site web et vos CGU. Si votre Marketing parle d’une remise sur les manteaux pudiques d’hiver, la même mention doit exister sur la fiche produit qu’ouvre le bouton call-to-action. Meta vérifie systématiquement la cohérence en suivant l’URL — un atterrissage sur une page sans rapport déclenche un rejet pour contenu trompeur.

Troisièmement, surveillez la qualité de votre numéro. Le tableau Quality rating de WhatsApp Manager affiche un score (Vert, Jaune, Rouge) calculé sur les blocages et signalements des 7 derniers jours. Un numéro Rouge voit ses templates rejetés deux fois plus souvent et passe en limite réduite. Pour préserver le score, segmentez vos envois, ne sollicitez que les utilisateurs qui ont opté explicitement pour WhatsApp, et offrez toujours un moyen simple de se désabonner via un quick-reply.

Enfin, gardez une trace versionnée de chaque template : nom, catégorie, payload JSON, date de soumission, date d’approbation, motif éventuel de rejet. Un fichier YAML par template dans un dépôt Git suffit, et vous remerciera le jour où Meta enverra une notification de pause générale sur un compte que vous aurez à diagnostiquer en quelques minutes.

Tutoriels frères

Pour aller plus loin

FAQ

Combien de templates puis-je créer sur un même WABA ?

Le plafond officiel est de 6 000 templates par WhatsApp Business Account, toutes langues et catégories confondues. Au-delà, l’API renvoie une erreur (#100) Template count limit reached. En pratique, on dépasse rarement quelques dizaines, car un même nom couvre plusieurs langues et plusieurs versions.

Puis-je modifier un template approuvé sans le re-soumettre ?

Depuis 2023, Meta autorise l’édition d’un template approuvé une fois par 24 heures, mais seulement pour le corps, l’en-tête, le pied de page et les boutons. La catégorie ne peut pas être changée — il faut alors créer un nouveau template avec un nom différent. Toute édition replace le template en PENDING jusqu’à validation.

Comment intégrer un paiement mobile dans un template ?

Les templates ne déclenchent pas directement un paiement, mais un bouton call-to-action de type URL peut pointer vers une page de paiement Wave, Orange Money ou Mixx by Yas. Le client clique, atterrit sur l’opérateur, valide et revient via un retour applicatif que vous gérez côté webhook bancaire — pas côté webhook WhatsApp.

Pourquoi mon template Authentication ne s’affiche-t-il pas comme prévu ?

Depuis avril 2024, le rendu d’un template Authentication est entièrement contrôlé par WhatsApp côté client. Vous ne définissez que la mention de sécurité et l’expiration du code ; tout le reste (texte « Voici votre code », formatage, boutons) est imposé par la plateforme et localisé automatiquement selon la langue du téléphone. C’est voulu : Meta cherche à uniformiser la perception des OTP pour réduire le phishing.

Que se passe-t-il si je dépasse mon quota mensuel de conversations Marketing ?

Aucun plafond mensuel ne bloque techniquement les envois Marketing tant que votre numéro reste vert. En revanche, chaque conversation Marketing déclenchée hors fenêtre est facturée au tarif Marketing du pays du destinataire. Le pilotage du coût se fait donc en amont, dans votre code d’envoi, en imposant des règles métier (par exemple, pas plus d’un Marketing par client et par semaine), pas en aval par Meta.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité