# Campagnes

> Index de la documentation : https://wahasend.com/docs/fr/llms.txt · Tout en un fichier : https://wahasend.com/docs/fr.md · URL de base de l'API : https://app.wahasend.com/api/v1

Une campagne envoie un modèle avec des `{{variables}}` à une liste, avec 3 à 7 secondes entre deux messages, tout de suite ou à une heure donnée. Inclus dans **Notify** (fonction `campaigns`). Statuts : `draft` ⇄ `scheduled` → `sending` ⇄ `paused` → `completed` ; `scheduled` ou `paused` → `cancelled`. `stats` compte `sent`, `failed`, `delivered` et `read` (d'après les accusés WhatsApp, chaque message une fois).

<a id="campaign-create"></a>

### Créer une campagne

`POST /api/v1/bulk/campaigns`

L'enregistre en `draft`, ou `scheduled` si vous donnez `scheduledAt`. Rien ne part avant l'appel à send (ou l'heure prévue).

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Corps de la requête**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `name` | string | oui | 1 à 255 caractères. |
| `template` | string | oui | 1 à 4096 caractères. Les champs comme `{{name}}` sont remplis avec les `variables` de chaque destinataire (clés dans n'importe quelle langue). |
| `recipients` | array | oui | 1 à 10 000 destinataires. |
| `recipients[].phone` | string | oui | Numéro international, 8 à 20 caractères (`+22212345678`). Les identifiants `@lid` ne sont pas acceptés ici. |
| `recipients[].variables` | object (string → string) | non | Valeurs du modèle. |
| `scheduledAt` | string (ISO 8601) | non | Quand commencer, avec n'importe quel décalage : `2026-10-05T08:00:00Z` ou `2026-10-05T08:00:00+00:00` (Nouakchott est en UTC). Vérifié chaque minute ; part de votre numéro par défaut. |

**Exemple**

curl:

```bash
curl -X POST https://app.wahasend.com/api/v1/bulk/campaigns \
  -H "X-API-Key: $WAHASEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Ramadan hours",
  "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
  "recipients": [
    {
      "phone": "+22212345678",
      "variables": {
        "name": "Aïcha"
      }
    },
    {
      "phone": "+22287654321",
      "variables": {
        "name": "Moussa"
      }
    }
  ]
}'
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "name": "Ramadan hours",
    "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
    "recipients": [
      {
        "phone": "+22212345678",
        "variables": {
          "name": "Aïcha"
        }
      },
      {
        "phone": "+22287654321",
        "variables": {
          "name": "Moussa"
        }
      }
    ]
  }),
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.post(
    "https://app.wahasend.com/api/v1/bulk/campaigns",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
    json={
        "name": "Ramadan hours",
        "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
        "recipients": [
            {
                "phone": "+22212345678",
                "variables": {
                    "name": "Aïcha",
                },
            },
            {
                "phone": "+22287654321",
                "variables": {
                    "name": "Moussa",
                },
            },
        ],
    },
)
print(r.json())
```

**Réponse 201**

```json
{
  "success": true,
  "campaign": {
    "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
    "name": "Ramadan hours",
    "status": "draft",
    "recipientCount": 2,
    "scheduledAt": null
  }
}
```

**Erreurs possibles**

- [`VALIDATION_ERROR`](https://wahasend.com/docs/fr/errors.md#validation_error) (400): Validation failed. Check the details for specific field errors.

<a id="campaign-list"></a>

### Lister les campagnes

`GET /api/v1/bulk/campaigns`

Toutes les campagnes de l'organisation, les plus anciennes d'abord.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Exemple**

curl:

```bash
curl https://app.wahasend.com/api/v1/bulk/campaigns \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns', {
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.get(
    "https://app.wahasend.com/api/v1/bulk/campaigns",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "campaigns": [
    {
      "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
      "name": "Ramadan hours",
      "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
      "status": "completed",
      "stats": {
        "total": 2,
        "sent": 2,
        "delivered": 2,
        "failed": 0,
        "read": 1
      },
      "scheduledAt": null,
      "createdAt": "2026-09-30T09:12:44.120Z"
    }
  ]
}
```

<a id="campaign-status"></a>

### Statut d'une campagne

`GET /api/v1/bulk/campaigns/:id/status`

Où en est une campagne, avec ses destinataires et ses compteurs.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

> `delivered` compte un message la première fois que WhatsApp le dit remis ou lu ; `read` la première fois qu'il est lu. Les campagnes d'avant le 2026-10-01 n'ont pas de `read`.

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Exemple**

curl:

```bash
curl https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/status \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/status', {
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.get(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/status",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
  "name": "Ramadan hours",
  "template": "Hello {{name}}, from Monday we open 10:00–16:00.",
  "recipients": [
    {
      "phone": "+22212345678",
      "variables": {
        "name": "Aïcha"
      }
    }
  ],
  "status": "sending",
  "stats": {
    "total": 2,
    "sent": 1,
    "delivered": 1,
    "failed": 0,
    "read": 0
  },
  "scheduledAt": null,
  "startedAt": "2026-09-30T09:15:02.000Z",
  "completedAt": null,
  "createdAt": "2026-09-30T09:12:44.120Z"
}
```

**Erreurs possibles**

- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.

<a id="campaign-update"></a>

### Modifier avant l'envoi

`PUT /api/v1/bulk/campaigns/:id`

Change le nom, le modèle, les destinataires ou l'heure de départ d'une campagne `draft` ou `scheduled`.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Corps de la requête**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `name` | string | non | 1 à 255 caractères. |
| `template` | string | non | 1 à 4096 caractères. |
| `recipients` | array | non | Remplace toute la liste (1 à 10 000). |
| `recipients[].phone` | string | oui | Numéro international, 8 à 20 caractères (`+22212345678`). Les identifiants `@lid` ne sont pas acceptés ici. |
| `recipients[].variables` | object (string → string) | non | Valeurs du modèle. |
| `scheduledAt` | string (ISO 8601) \| null | non | Une nouvelle heure (tout décalage) la rend `scheduled` ; `null` la remet en `draft`. |

**Exemple**

curl:

```bash
curl -X PUT https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71 \
  -H "X-API-Key: $WAHASEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "template": "Hello {{name}}, from Monday we open 10:00–16:30.",
  "scheduledAt": "2026-10-05T08:00:00+00:00"
}'
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71', {
  method: 'PUT',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "template": "Hello {{name}}, from Monday we open 10:00–16:30.",
    "scheduledAt": "2026-10-05T08:00:00+00:00"
  }),
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.put(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
    json={
        "template": "Hello {{name}}, from Monday we open 10:00–16:30.",
        "scheduledAt": "2026-10-05T08:00:00+00:00",
    },
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "campaign": {
    "id": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
    "name": "Ramadan hours",
    "template": "Hello {{name}}, from Monday we open 10:00–16:30.",
    "status": "scheduled",
    "stats": {
      "total": 2,
      "sent": 0,
      "delivered": 0,
      "failed": 0
    },
    "scheduledAt": "2026-10-05T08:00:00.000Z",
    "createdAt": "2026-09-30T09:12:44.120Z"
  }
}
```

**Erreurs possibles**

- [`CAMPAIGN_INVALID_STATE`](https://wahasend.com/docs/fr/errors.md#campaign_invalid_state) (400): The campaign cannot do this in its current state.
- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.
- [`VALIDATION_ERROR`](https://wahasend.com/docs/fr/errors.md#validation_error) (400): Validation failed. Check the details for specific field errors.

<a id="campaign-send"></a>

### Lancer l'envoi

`POST /api/v1/bulk/campaigns/:id/send`

Lance maintenant une campagne `draft` ou `scheduled`. Les messages partent à 3–7 secondes d'intervalle.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Corps de la requête**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `containerId` | uuid | non | Lequel de vos numéros WhatsApp utiliser ; il l'emporte toujours. Par défaut : votre numéro par défaut (sinon un numéro connecté), ou un numéro du groupe quand [plusieurs numéros](https://wahasend.com/docs/fr/phone-numbers.md#several-numbers) est activé. Ignoré avec une clé de numéro, qui utilise toujours son numéro. |

**Exemple**

curl:

```bash
curl -X POST https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/send \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/send', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.post(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/send",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "campaignId": "c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
  "status": "sending",
  "totalRecipients": 2,
  "estimatedDuration": "1 minutes"
}
```

**Erreurs possibles**

- [`CAMPAIGN_INVALID_STATE`](https://wahasend.com/docs/fr/errors.md#campaign_invalid_state) (400): The campaign cannot do this in its current state.
- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.
- [`NO_SESSION_CONFIGURED`](https://wahasend.com/docs/fr/errors.md#no_session_configured) (400): This account has no connected WhatsApp number.

<a id="campaign-pause"></a>

### Mettre en pause

`POST /api/v1/bulk/campaigns/:id/pause`

Arrête les messages pas encore partis. Seule une campagne `sending` peut être mise en pause.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Exemple**

curl:

```bash
curl -X POST https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/pause \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/pause', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.post(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/pause",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "status": "paused",
  "jobsRemoved": 118
}
```

**Erreurs possibles**

- [`CAMPAIGN_INVALID_STATE`](https://wahasend.com/docs/fr/errors.md#campaign_invalid_state) (400): The campaign cannot do this in its current state.
- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.

<a id="campaign-resume"></a>

### Reprendre

`POST /api/v1/bulk/campaigns/:id/resume`

Envoie ce qu'il restait à une campagne `paused`, jamais depuis le début.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Corps de la requête**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `containerId` | uuid | non | Lequel de vos numéros WhatsApp utiliser ; il l'emporte toujours. Par défaut : votre numéro par défaut (sinon un numéro connecté), ou un numéro du groupe quand [plusieurs numéros](https://wahasend.com/docs/fr/phone-numbers.md#several-numbers) est activé. Ignoré avec une clé de numéro, qui utilise toujours son numéro. |

**Exemple**

curl:

```bash
curl -X POST https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/resume \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/resume', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.post(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/resume",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "status": "sending",
  "jobsRequeued": 118
}
```

**Erreurs possibles**

- [`CAMPAIGN_INVALID_STATE`](https://wahasend.com/docs/fr/errors.md#campaign_invalid_state) (400): The campaign cannot do this in its current state.
- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.
- [`NO_SESSION_CONFIGURED`](https://wahasend.com/docs/fr/errors.md#no_session_configured) (400): This account has no connected WhatsApp number.

<a id="campaign-delete"></a>

### Supprimer

`DELETE /api/v1/bulk/campaigns/:id`

Supprime une campagne qui n'est pas `sending` (mettez-la en pause d'abord) et son historique de messages.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Exemple**

curl:

```bash
curl -X DELETE https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71 \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71', {
  method: 'DELETE',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.delete(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true
}
```

**Erreurs possibles**

- [`CAMPAIGN_INVALID_STATE`](https://wahasend.com/docs/fr/errors.md#campaign_invalid_state) (400): The campaign cannot do this in its current state.
- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.

<a id="campaign-cancel"></a>

### Annuler

`POST /api/v1/bulk/campaigns/:id/cancel`

Annule pour de bon une campagne `scheduled` ou `paused` : statut `cancelled`, les messages pas encore partis sont abandonnés (marqués `failed`, erreur « Campaign cancelled »). Pour arrêter une campagne `sending`, mettez-la d'abord en pause.

- Débloqué par: Notify (`campaigns`) + Developer ou Connect pour une clé d'API
- Clé de numéro : oui

**Paramètres de chemin**

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `id` | uuid | oui | Identifiant de la campagne. |

**Exemple**

curl:

```bash
curl -X POST https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/cancel \
  -H "X-API-Key: $WAHASEND_API_KEY"
```

JavaScript:

```js
const res = await fetch('https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/cancel', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.WAHASEND_API_KEY },
});
const data = await res.json();
```

Python:

```python
import os
import requests

r = requests.post(
    "https://app.wahasend.com/api/v1/bulk/campaigns/c1f9a2d4-6b3e-4a7c-9d15-3e8b2f6a0c71/cancel",
    headers={"X-API-Key": os.environ["WAHASEND_API_KEY"]},
)
print(r.json())
```

**Réponse 200**

```json
{
  "success": true,
  "status": "cancelled",
  "jobsRemoved": 0,
  "messagesCancelled": 118
}
```

**Erreurs possibles**

- [`CAMPAIGN_INVALID_STATE`](https://wahasend.com/docs/fr/errors.md#campaign_invalid_state) (400): The campaign cannot do this in its current state.
- [`NOT_FOUND`](https://wahasend.com/docs/fr/errors.md#not_found) (404): Not found.
