Mon template est refusé par Meta : où lire la cause et comment la corriger

La cause se lit à deux endroits : l'erreur (#code) renvoyée à la création (400 avant Meta, 502 après) et rejected_reason dans GET /v1/templates une fois le statut REJECTED. Vous ne pouvez pas éditer un template : corrigez-le puis recréez-le.

Mon template est refusé par Meta : où lire la cause et comment la corriger

Astuce
La cause se lit à deux endroits : l'erreur (#code) renvoyée à la création (400 avant Meta, 502 après) et rejected_reason dans GET /v1/templates une fois le statut REJECTED. Vous ne pouvez pas éditer un template : corrigez-le puis recréez-le.

Scénario

Vous créez un template et il reste en PENDING, puis passe en REJECTED. Ou bien la création elle-même répond une erreur. Oui, la cause est lisible, mais pas toujours au même endroit. Voici où chercher, dans l'ordre.

Où lire la cause

POST /v1/templates
  ├─ 422  champ invalide (nom, longueur, boutons)           avant Meta
  ├─ 400  règle de variables ou de boutons non respectée    avant Meta, message précis
  ├─ 502  Meta refuse à la soumission : « (#code) titre — détail »
  └─ 201  soumis, status PENDING
        │   (Meta examine)
        ▼
GET /v1/templates
  └─ status APPROVED  → utilisable
     status REJECTED  → rejected_reason = la raison de Meta, telle quelle

curl

curl -X GET "https://wa-api.geskap.com/v1/templates" \
  -H "Authorization: Bearer $GESKAP_API_KEY"

Node.js

const res = await fetch("https://wa-api.geskap.com/v1/templates", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
  },
});
console.log(res.status, await res.json());

PHP

$ch = curl_init("https://wa-api.geskap.com/v1/templates");
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("GESKAP_API_KEY"),
  ],
]);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $res;

Python

import os, requests

res = requests.request(
    "GET",
    "https://wa-api.geskap.com/v1/templates",
    headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
    timeout=15,
)
print(res.status_code, res.json())

rejected_reason ne contient quelque chose que si le status est REJECTED. Sa valeur est celle de Meta, sans reformulation : un code comme INVALID_FORMAT, INCORRECT_CATEGORY, TAG_CONTENT_MISMATCH, SCAM ou ABUSIVE_CONTENT, ou une phrase. Elle se lit en listant les templates : la liste se synchronise avec Meta à cet appel.

Les causes que l'API vous dit elle-même (400, avant Meta)

Ces refus ne coûtent rien et ne partent pas chez Meta :

Message ou causeCorrection
Variable vide {{}}Retirez-la ou nommez-la : {{1}} ou {{nom}}
Variables numérotées et nommées mélangéesUne seule forme dans tout le template
Variables numérotées avec un trou ({{1}} puis {{3}})Numérotez de {{1}} à {{n}} sans trou
Moins de example_values que de variablesUne valeur d'exemple par variable, dans l'ordre
Variable nommée avec un caractère interditLettres, chiffres et _ uniquement
En-tête texte de plus de 60 caractères, sur plusieurs lignes, ou avec plus d'une variableUne ligne, 60 caractères, au plus une variable {{1}}
Lien wa.me dans un bouton lienUtilisez un bouton de réponse rapide (kind: quick_reply)
Lien variable mal forméUne seule variable {{1}}, à la fin de l'URL, avec url_example complet en https
Nom du templateMinuscules, chiffres et _ uniquement (sinon 422)

Les causes que Meta renvoie (502 ou REJECTED)

Ce que Meta renvoieCauseCorrection
(#132000) nombre de paramètres incorrectVariables du corps différentes des valeurs fourniesMêmes nombres à la création et à l'envoi
(#132001) le template n'existe pasMauvais nom ou mauvaise langue, ou pas encore APPROVEDNom et langue exacts du template approuvé
INVALID_FORMAT ou exemple manquantUne variable n'a pas d'exempleUne entrée example_values par variable
Variable au début ou à la fin du corps, ou deux variables collées {{1}}{{2}}Interdit par MetaMettez du texte ou une espace autour de chaque variable
(2388081) lien wa.meMeta refuse les liens WhatsApp en bouton lienBouton quick_reply
INCORRECT_CATEGORYLa catégorie choisie ne correspond pas au contenu, selon MetaRecréez avec la catégorie qui correspond au contenu
TAG_CONTENT_MISMATCH, SCAM, ABUSIVE_CONTENTContenu jugé non conforme par MetaRéécrivez le contenu ; l'API ne peut pas contester le verdict
2494160, numéro « Hors ligne »Le numéro n'est pas connecté à l'API CloudConnectez et vérifiez le numéro dans WhatsApp Manager, puis recommencez
Catégorie AUTHENTICATION refuséeVotre entreprise Meta doit être vérifiée (Business Verification)Faites vérifier votre entreprise dans Meta Business Manager

Cette table reprend ce que l'API et sa documentation établissent. Pour tout autre code, le message de Meta est renvoyé tel quel : c'est lui qui fait foi.

Corriger : on ne modifie pas, on recrée

Il n'existe pas de route de modification pour un développeur. Procédure :

  1. Lisez la cause (rejected_reason ou le message (#code)).
  2. Supprimez l'ancien : DELETE /v1/templates/{name} (toutes les langues).
  3. Recréez-le corrigé avec POST /v1/templates, de préférence sous un nouveau nom (rappel_rdv_v2). Si Meta refuse la suppression, l'API ne fait que masquer l'ancien chez vous : il peut encore exister chez Meta.
  4. Attendez APPROVED en relisant GET /v1/templates.

Il n'y a pas d'événement de webhook pour le statut d'un template : interrogez la liste.

À l'envoi

Un template qui n'est pas APPROVED répond 400 « Le template doit être APPROVED par Meta avant l'envoi. ». Un template introuvable (nom ou langue faux) répond 400 « Template introuvable ». Créer et lister des templates ne coûte aucun crédit chez Geskap.

Attention
Piège : un template approuvé sur un numéro n'existe pas sur un autre. Si vous avez plusieurs numéros, voir Plusieurs numéros.
Attention
Piège : PENDING n'est pas un échec. Tant que Meta n'a pas répondu, ne recréez pas : vous créeriez un doublon. Attendez le statut.
Attention
Piège : un 502 à la création n'est pas une panne de l'API : c'est Meta qui a refusé, et son message est dans la réponse. Lisez-le avant de réessayer.

Pour un template qui passe du premier coup, voir Écrire à un client qui ne vous a jamais écrit et Template à boutons de réponse rapide.

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