Envoyer une campagne WhatsApp par API
Envoyer une campagne WhatsApp par API : template marketing, destinataires, lancement, quotas par forfait, limites marketing de Meta et suivi des envois.
Pour envoyer une campagne WhatsApp par API avec Genuka WA, vous faites approuver un template
MARKETING par Meta, vous créez la campagne avec POST /api/v1/campaigns et sa liste de
destinataires, puis vous la lancez avec POST /api/v1/campaigns/{id}/launch. Chaque destinataire
est suivi jusqu'à la lecture, et Meta facture les messages délivrés directement à votre propre
compte WhatsApp Business.
Mis à jour le 8 octobre 2026
Ce qu'il faut avant d'envoyer une campagne
- Un numéro connecté et son
connectionId— voir Connecter un numéro. - Une clé API, utilisée uniquement côté serveur — voir Authentification.
- Un moyen de paiement sur votre compte Meta. Genuka est Meta Tech Provider, pas BSP : Meta
facture votre compte WhatsApp Business (WABA) directement, et un client onboardé par un Tech
Provider doit y ajouter son propre moyen de paiement
(Meta, Partners).
Sans lui, le template est approuvé mais chaque envoi revient en erreur
131042. - Des destinataires qui ont accepté de recevoir vos messages. C'est une règle de WhatsApp, pas une bonne pratique — la section sur l'opt-in, plus bas, la détaille.
Comment créer le template marketing ?
Hors de la fenêtre de service de 24 heures, seul un template approuvé est délivré. Une campagne en
utilise toujours un. Soumettez-le avec la catégorie MARKETING :
curl -X POST https://wa.genuka.com/api/v1/templates \
-H "Authorization: Bearer $GENUKA_WA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"connectionId": "con_1",
"name": "promo_octobre",
"language": "fr",
"category": "MARKETING",
"components": [
{ "type": "BODY",
"text": "Bonjour {{1}}, -20 % sur toute la boutique jusqu’à dimanche.",
"example": { "body_text": [["Awa"]] } },
{ "type": "BUTTONS", "buttons": [
{ "type": "URL", "text": "Voir les offres", "url": "https://example.com/promo" }
] }
]
}'La réponse est un 201 qui porte l'id du template et son statut. Meta l'examine —
l'examen peut prendre jusqu'à 24 heures
(Meta, Template fundamentals).
Le verdict arrive sur vos webhooks (template.status_changed) et sur
GET /api/v1/templates/{id}. Une campagne ne part qu'avec un template approved.
Chaque variable du corps ({{1}}, {{2}}…) exige un exemple, sinon le template est refusé. La
référence API couvre les en-têtes média, les paramètres nommés et les
boutons.
Comment créer et lancer la campagne ?
Créez la campagne
POST /api/v1/campaigns prend quatre champs, tous obligatoires : connectionId, templateId,
name et recipients. Chaque destinataire porte son numéro au format international (+ et
indicatif pays) et ses propres variables. La campagne est créée en statut draft : rien n'est
encore envoyé.
Lancez-la
POST /api/v1/campaigns/{id}/launch envoie chaque destinataire encore pending et répond avec le
décompte : sent, failed, skipped. Un sent veut dire que Meta a accepté le message, pas qu'il
est arrivé — la livraison et la lecture arrivent ensuite, par webhook.
Suivez les statuts
Lisez les compteurs sur GET /api/v1/campaigns/{id} et le détail par destinataire sur
GET /api/v1/campaigns/{id}/recipients. La section sur le suivi, plus bas, détaille les deux.
# 1. Créer la campagne (statut draft)
curl -X POST https://wa.genuka.com/api/v1/campaigns \
-H "Authorization: Bearer $GENUKA_WA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"connectionId": "con_1",
"templateId": "tpl_123",
"name": "Promo octobre",
"recipients": [
{ "to": "+237690000001", "variables": ["Awa"] },
{ "to": "+237690000002", "variables": ["Paul"] }
]
}'
# { "data": { "id": "cmp_9", "name": "Promo octobre", "status": "draft", "_count": { "recipients": 2 } } }
# 2. La lancer
curl -X POST https://wa.genuka.com/api/v1/campaigns/cmp_9/launch \
-H "Authorization: Bearer $GENUKA_WA_API_KEY"
# { "data": { "sent": 2, "failed": 0, "skipped": 0 } }variables est un tableau positionnel pour les paramètres du corps. Pour un en-tête média, un
bouton dynamique ou des paramètres nommés, passez un objet à la place —
{ "body": [...], "bodyNamed": { "first_name": "Awa" }, "header": {...}, "buttons": [...] } —
la même forme que l'envoi d'un template. Les paramètres d'un template à
paramètres nommés vont dans bodyNamed : placés dans body, ils partiraient comme des
paramètres positionnels.
Pourquoi le lancement est-il refusé ?
Ces contrôles ont lieu avant le premier envoi : un lancement refusé n'a rien envoyé. Les refus les plus courants :
| Statut | Code | Cause |
|---|---|---|
402 | plan_limit_messages | La liste ne tient pas dans le quota restant de la période. Tous les destinataires pending comptent, y compris ceux qui seront ensuite écartés comme désinscrits |
402 | subscription_past_due | L'essai ou la période payée est échu |
400 | send_template | Le template n'est pas approved (en examen, refusé, en pause) — le message dit lequel |
409 | send_config | Le numéro a été déconnecté de l'API depuis l'application WhatsApp Business (coexistence) : reconnectez-le |
409 | number_released | Le numéro a été libéré de votre forfait : reconnectez-le par l'Embedded Signup |
403 | account_deactivated | Le client propriétaire du numéro est suspendu |
404 | campaign_not_found | L'id n'existe pas ou n'est pas à la portée de votre clé |
À la création, un templateId et un connectionId qui appartiennent à deux clients différents
répondent 400 template_connection_mismatch, et une liste sans aucun to exploitable
400 no_valid_recipients. Les autres codes sont dans la référence des erreurs.
Combien de messages une campagne peut-elle envoyer ?
Genuka ne facture jamais le message. Votre forfait inclut en revanche un quota de messages sortants par numéro payé et par période de facturation, partagé entre les envois API et les destinataires de campagne. Le quota de la période vaut : numéros payés × quota unitaire du palier. Le compteur repart de zéro à chaque nouvelle période : chaque mois sur un abonnement mensuel, au renouvellement sur un abonnement annuel.
| Palier | Numéros max | Messages inclus par numéro et par période |
|---|---|---|
| Starter | 5 | 500 |
| Growth | 15 | 5 000 |
| Scale | 100 | 30 000 |
| Enterprise | sur mesure | sur mesure |
Exemple : 3 numéros en Growth donnent 15 000 messages pour la période. L'essai gratuit de 7 jours
tourne sur le palier Growth avec un numéro, soit 5 000 messages. Seuls les messages acceptés par
Meta sont décomptés : un envoi que Meta refuse à l'appel ne consomme rien, mais un message accepté
puis signalé failed par webhook reste décompté. Les tarifs sont sur la
page de prix et en Markdown sur /pricing.md.
Quelles limites Meta impose-t-il aux campagnes marketing ?
Le quota Genuka n'est pas la seule limite. Meta en applique quatre, indépendantes de votre forfait :
| Limite Meta | Ce qu'elle dit | Ce que vous voyez |
|---|---|---|
| Plafond d'envoi | Nombre de destinataires uniques joignables hors fenêtre de service, par 24 heures glissantes, au niveau du portefeuille Business : 250 pour un portefeuille neuf, puis 2 000, 10 000, 100 000, illimité (doc) | WhatsApp Manager, Account tools > Messaging limits (même page). Le messagingLimitTier de GET /api/v1/numbers?refresh=true n'est qu'indicatif : il vient d'un champ que Meta a déprécié et peut être vide |
| Plafond marketing par utilisateur | WhatsApp peut ne pas délivrer un template marketing à quelqu'un qui en reçoit beaucoup et en lit peu. Attendez au moins 24 heures avant de réessayer (doc) | Erreur 131049 sur le webhook de statut, destinataire failed |
| Numéros des États-Unis | WhatsApp ne délivre pas actuellement de templates marketing aux numéros américains (même page) | Échec du destinataire |
| Débit | 80 messages par seconde par numéro par défaut, 20 pour un numéro en coexistence (débit, coexistence) | Le lancement est cadencé dessus |
Le plafond marketing par utilisateur n'est pas actif pour les envois depuis ou vers l'Espace économique européen, le Royaume-Uni, le Japon et la Corée du Sud (même page Meta).
Les templates MARKETING d'une campagne sont d'abord proposés à la
Marketing Messages API
de Meta ; si votre compte n'y a pas accès, l'envoi repasse sur l'endpoint classique sans
interrompre la campagne.
Combien coûte une campagne chez Meta ?
Meta facture par message délivré, au tarif de la catégorie du template et de l'indicatif du pays du destinataire, sur votre portefeuille Business (Meta, Pricing). Genuka n'y ajoute aucune marge et ne voit jamais passer ce paiement.
Faut-il un opt-in pour une campagne WhatsApp ?
Oui. La politique WhatsApp Business n'autorise à contacter quelqu'un que s'il vous a donné son numéro et a confirmé vouloir recevoir vos messages (WhatsApp Business Messaging Policy). Meta précise que la demande doit nommer votre entreprise et dire clairement à quoi la personne s'abonne, par le canal de votre choix — site, SMS, formulaire papier (Meta, Get opt-in). Une qualité durablement basse fait limiter le numéro par Meta (même page).
Genuka applique la désinscription pour vous sur les campagnes marketing :
- Quand un utilisateur arrête les messages marketing depuis WhatsApp, Meta l'annonce par webhook ;
Genuka l'enregistre. Un envoi refusé avec
131050(« ce destinataire a choisi de ne plus recevoir de messages marketing ») l'enregistre aussi. - Au lancement d'une campagne
MARKETING, ces contacts sont écartés avant tout envoi et passent en statutskipped, avec le motif. Ils ne consomment ni quota ni facturation Meta. - Les campagnes
UTILITYetAUTHENTICATIONne sont pas filtrées : ce ne sont pas des messages marketing.
Un mot-clé maison (« répondez STOP ») n'est pas interprété automatiquement : les réponses vous
arrivent sur message.received, et c'est à vous de retirer ces contacts de vos listes.
Comment suivre les résultats d'une campagne ?
GET /api/v1/campaigns/{id} renvoie la campagne, son template, son numéro et un objet stats qui
compte les destinataires par statut :
{
"data": {
"id": "cmp_9",
"name": "Promo octobre",
"status": "completed",
"template": { "id": "tpl_123", "name": "promo_octobre", "language": "fr", "status": "approved" },
"_count": { "recipients": 1200 },
"stats": { "read": 640, "delivered": 410, "sent": 95, "failed": 41, "skipped": 14 }
}
}Chaque destinataire n'est compté qu'une fois, sous son statut le plus avancé : un message lu
figure dans read, pas dans delivered. Le taux de livraison se lit donc
(delivered + read) / (total − skipped).
| Statut | Signification |
|---|---|
pending | Pas encore envoyé |
sent | Accepté par Meta |
delivered | Arrivé sur le téléphone |
read | Lu — seulement si le destinataire a activé les confirmations de lecture |
failed | Refusé, avec le motif de Meta dans errorMessage |
skipped | Écarté au lancement : désinscrit du marketing |
Pour les échecs, GET /api/v1/campaigns/{id}/recipients?status=failed&limit=1000 liste chaque
destinataire avec errorMessage, sentAt, deliveredAt, readAt et failedAt (200 lignes par
défaut, 1 000 au maximum). En temps réel, abonnez un endpoint à message.delivered,
message.read, message.failed et user_preference.stopped — voir Webhooks.
Comment renvoyer aux destinataires bloqués par le plafond marketing ?
Le plafond marketing par utilisateur se signale après l'envoi : Meta accepte le message, puis le
webhook de statut revient failed avec l'erreur 131049
(Meta, Per-user limits).
Le destinataire passe en failed, avec le texte de Meta dans errorMessage (Meta décrit cette
erreur ainsi : « This message was not delivered to maintain healthy ecosystem engagement »). Un
nouvel appel à launch ne le renverra pas : il ne reprend que les destinataires pending.
Pour retenter ces personnes, attendez au moins 24 heures, listez
GET /api/v1/campaigns/{id}/recipients?status=failed, gardez ceux qui portent ce motif (ou le code
131049 reçu sur message.failed) et créez une nouvelle campagne avec eux. Dans le cas plus rare
où Meta refuse l'envoi lui-même avec 131049, le destinataire reste pending, et un nouvel appel à
launch 24 heures plus tard le reprend.
Limites de la version actuelle
- Le lancement est synchrone et borné dans le temps. L'appel parcourt la liste un destinataire
après l'autre : chaque envoi attend la réponse de Meta puis l'enregistrement de son statut, si
bien que le débit réel reste bien en dessous du plafond du numéro. Au-delà de 2 minutes environ,
le CDN qui protège l'API répond
524— une page d'erreur, pas du JSON — alors que l'envoi continue côté serveur (Cloudflare, erreur 524). Gardez des campagnes de quelques centaines de destinataires et découpez une grosse audience en plusieurs campagnes. - Après un
524, suivez la campagne au lieu de la relancer. InterrogezGET /api/v1/campaigns/{id}jusqu'à ce questatusne soit plusrunning. N'appelez jamaislaunchsur une campagnerunning: rien ne l'en empêche aujourd'hui, et deux exécutions en parallèle enverraient deux fois le message aux destinataires que la première n'a pas encore atteints. - Une exécution trop longue est interrompue. Le serveur ne laisse pas un appel tourner
indéfiniment. Si la campagne est encore
running15 minutes après l'appel, l'exécution a été coupée : les destinataires restéspendingn'ont pas été envoyés, et un nouvel appel àlaunchles reprend. - Pas de planification. Aucun champ de date : appelez
launchau moment voulu, depuis votre propre tâche planifiée.
Et si je préfère une interface plutôt qu'une API ?
Genuka WA n'a pas de console de campagnes : /api/v1/campaigns est une brique d'intégration
(template + destinataires + statuts). Si vous voulez segmenter une clientèle et lancer des
campagnes sans écrire de code, Genuka Core, la plateforme de gestion
commerciale de Genuka, le fait : elle catégorise vos clients, analyse leur comportement d'achat
et lance des campagnes WhatsApp, SMS et email ciblées.
FAQ
Puis-je envoyer une campagne à des contacts qui ne m'ont jamais écrit ?
Oui, avec un template approuvé et leur opt-in. C'est précisément le rôle du template : il est le seul message délivré hors de la fenêtre de 24 heures. Le plafond d'envoi de Meta (250 destinataires uniques par 24 heures pour un portefeuille neuf) s'applique à ces envois.
Combien coûte une campagne WhatsApp avec Genuka WA ?
Deux lignes séparées. Meta facture chaque template délivré à votre portefeuille Business, selon la catégorie et le pays du destinataire. Genuka facture un abonnement par numéro WhatsApp, avec un quota de messages inclus, et ne prend aucune marge sur les tarifs de Meta.
Que se passe-t-il si un destinataire s'est désinscrit ?
Sur une campagne MARKETING, il est écarté avant l'envoi et marqué skipped. Il ne consomme pas
votre quota et Meta ne vous facture rien pour lui.
Pourquoi sent est-il élevé mais delivered faible ?
sent signifie seulement que Meta a accepté le message. Les accusés de livraison arrivent ensuite
par webhook ; s'ils ne viennent pas, regardez failed et les erreurs 131049 (plafond marketing)
ou 131026 (destinataire injoignable).
Puis-je relancer la même campagne ?
Oui, une fois qu'elle n'est plus running (completed ou failed) : launch n'envoie alors que
les destinataires encore pending, jamais un message déjà parti. Ne la relancez pas pendant
qu'elle est running, même après un 524 : attendez qu'elle en sorte, ou 15 minutes si elle y
reste (voir les limites ci-dessus).
Sources
- Meta — Messaging limits
- Meta — Per-user marketing template message limits
- Meta — Throughput
- Meta — Pricing on the WhatsApp Business Platform
- Meta — Get opt-in for WhatsApp
- Meta — Template fundamentals
- Meta — Marketing Messages API: get started
- Meta — Partners (Tech Providers et Solution Partners)
- Meta — Error codes
- Meta — Onboard WhatsApp Business app users
- WhatsApp — Business Messaging Policy
- Cloudflare — Error 524: a timeout occurred
- Genuka — genuka.com