Campagnes
Une campagne, c’est un agent IA, un numéro WhatsApp et une audience. L’API te donne l’annuaire (ids, statut, état de connexion), l’interrupteur pause et reprise, et la porte pour les leads opt-in.
Endpoints
Section intitulée « Endpoints »| Méthode | Chemin | Scope |
|---|---|---|
| GET | /campaigns |
campaigns:read |
| POST | /campaigns/{id}/pause |
campaigns:write |
| POST | /campaigns/{id}/resume |
campaigns:write |
| POST | /campaigns/{id}/leads |
messages:send |
Lister les campagnes
Section intitulée « Lister les campagnes »curl "https://app.whatsetter.com/api/v1/campaigns" \ -H "Authorization: Bearer ws_live_…"const res = await fetch('https://app.whatsetter.com/api/v1/campaigns', { headers: { Authorization: 'Bearer ws_live_…' },});const { data: campaigns } = await res.json();import requests
r = requests.get( "https://app.whatsetter.com/api/v1/campaigns", headers={"Authorization": "Bearer ws_live_…"},)campaigns = r.json()["data"]{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c0c1", "campaign_id": "acme-france-1-ab12", "name": "Alex", "status": "active", "purpose": "setter", "whatsapp_connected": true, "created_at": "2026-08-01T09:00:00.000Z" } ]}| Champ | Signification |
|---|---|
id |
L’id du document campagne. Accepté dans tous les chemins /campaigns/{id}/.... |
campaign_id |
Le slug que les leads, conversations et rendez-vous portent dans leur propre campaign_id. Accepté aussi dans les chemins et les filtres. |
name |
Le nom d’affichage de l’agent. |
status |
active, draft, paused, archived, ou unknown pour une valeur interne. |
purpose |
setter (conversations 1-à-1) ou group (groupes WhatsApp). |
whatsapp_connected |
true quand le numéro de la campagne peut envoyer maintenant. |
La liste contient jusqu’à 100 campagnes, les plus récentes d’abord. Pas de curseur.
Pause et reprise
Section intitulée « Pause et reprise »Mettre en pause arrête les réponses de l’IA et les envois, comme l’interrupteur du dashboard. Reprendre les réactive.
curl -X POST "https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/pause" \ -H "Authorization: Bearer ws_live_…"const res = await fetch('https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/pause', { method: 'POST', headers: { Authorization: 'Bearer ws_live_…' },});const { data: campaign } = await res.json();import requests
r = requests.post( "https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/pause", headers={"Authorization": "Bearer ws_live_…"},)campaign = r.json()["data"]La réponse est l’objet campagne avec son nouveau status. Il n’existe que deux transitions :
| Appel | Autorisé depuis | Résultat | Sinon |
|---|---|---|---|
POST /campaigns/{id}/pause |
active |
paused |
409 invalid_state |
POST /campaigns/{id}/resume |
paused |
active |
409 invalid_state |
Une campagne draft doit être activée depuis le dashboard. Une campagne archived ne peut pas être reprise.
La reprise dépend de la limite de campagnes actives de ton plan : Free et Starter 1, Business 3, Scale 10, plus les agents supplémentaires ajoutés à ton plan. Quand la limite est atteinte, la reprise répond 402 plan_limit_reached : mets une autre campagne en pause ou change de plan.
Pousser un lead opt-in
Section intitulée « Pousser un lead opt-in »Quand quelqu’un s’inscrit sur ton funnel ou ton CRM, pousse-le vers la campagne. WhatSetter déroule le même pipeline que le webhook de page de vente de la campagne : validation du téléphone et vérification WhatsApp, déduplication contre les contacts déjà contactés, quota quotidien de premiers contacts, puis un premier message écrit par l’IA à partir du template de la campagne, du nom du lead et de chaque clé de additional_data.
curl -X POST "https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/leads" \ -H "Authorization: Bearer ws_live_…" \ -H "Content-Type: application/json" \ -d '{ "phone": "+33612345678", "name": "Julien", "email": "julien@example.com", "source_url": "crm:hubspot", "external_reference": "4471", "additional_data": { "offre": "Pack Pro", "ville": "Lyon", "budget": "500-1000" } }'const res = await fetch('https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/leads', { method: 'POST', headers: { Authorization: 'Bearer ws_live_…', 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: '+33612345678', name: 'Julien', email: 'julien@example.com', source_url: 'crm:hubspot', external_reference: '4471', additional_data: { offre: 'Pack Pro', ville: 'Lyon', budget: '500-1000' }, }),});const { data } = await res.json(); // 202import requests
r = requests.post( "https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/leads", headers={"Authorization": "Bearer ws_live_…"}, json={ "phone": "+33612345678", "name": "Julien", "email": "julien@example.com", "source_url": "crm:hubspot", "external_reference": "4471", "additional_data": {"offre": "Pack Pro", "ville": "Lyon", "budget": "500-1000"}, },)data = r.json()["data"] # 202{ "data": { "status": "accepted", "campaign_id": "acme-france-1-ab12", "phone": "+33612345678", "external_reference": "4471", "note": "Queued into the first-contact pipeline: deduplication, daily first-contact quota and anti-ban pacing apply. The lead is created later, so no lead id exists yet…" }}| Champ | Règles |
|---|---|
phone |
Obligatoire. Format international, 6 à 15 chiffres. Renvoyé avec un +. |
name, email |
Optionnels, coupés à 255 caractères. |
source_url |
Optionnel, 255 caractères maximum. D’où vient le lead. Vaut api par défaut. |
external_reference |
Optionnel, 255 caractères maximum. L’identifiant de ta propre fiche, stocké tel quel et renvoyé sur chaque lead et chaque webhook. |
additional_data |
Objet optionnel, 30 clés et 2000 caractères maximum une fois sérialisé. Sert à personnaliser le premier message, jamais stocké, jamais renvoyé. Les clés nommées comme les champs ci-dessus (phone, name, email, source_url, external_reference) sont ignorées. |
C’est asynchrone
Section intitulée « C’est asynchrone »L’endpoint répond 202 dès que le lead est accepté. La ligne lead est créée plus tard, après déduplication et cadencement, donc il n’y a pas encore d’id de lead. Pour suivre :
- retrouve le lead avec
GET /leads?external_reference=4471(ou?phone=+33612345678) ; - ou abonne-toi aux webhooks :
contact.external_referenceporte ton identifiant.
Un contact déjà contacté par la campagne est dédupliqué en silence : pas de second premier message, et le 202 est identique. Les leads au-delà du quota sont mis en file pour la fenêtre suivante, jamais perdus.
Deux budgets protègent le numéro, et l’API ne peut contourner ni l’un ni l’autre :
- Premiers contacts quotidiens par campagne : les leads opt-in au-delà attendent le lendemain.
- Messages quotidiens par numéro WhatsApp : partagés avec
POST /messages, voir Messages pour les en-têtesX-Quota-*.
En plus, les requêtes sont limitées par espace de travail et par minute selon le plan (429 rate_limited avec Retry-After).
Les erreurs que tu rencontreras
Section intitulée « Les erreurs que tu rencontreras »| HTTP | code |
Quand |
|---|---|---|
| 401 | missing_api_key, invalid_api_key |
Clé absente, inconnue ou révoquée. |
| 402 | plan_limit_reached |
Reprise refusée : la limite de campagnes actives du plan est atteinte. |
| 403 | insufficient_scope |
La clé n’a pas campaigns:read, campaigns:write ou messages:send. |
| 404 | not_found |
Campagne inconnue, ou campagne d’un autre espace de travail. |
| 409 | invalid_state |
Pause sur une campagne non active, reprise sur une campagne non en pause, lead poussé vers une campagne non active, ou campagne jamais ouverte dans le dashboard. |
| 422 | validation_error |
Téléphone invalide, additional_data qui n’est pas un objet ou trop gros, external_reference trop long. |
| 429 | rate_limited |
Trop de requêtes cette minute. Respecte Retry-After. |
| 502 | upstream_error |
Le pipeline de premier message était injoignable. Réessaie dans un instant. |

