Envoyer ou programmer

POST /api/v1/campaigns/{campaignId}/send Déclenche l'envoi et répond 202 immédiatement. L'envoi lui-même s'exécute en arrière-plan, cadencé selon le quota d'envoi — la requête ne l'attend jamais. Appelé sans corps, il envoie tout de suite. Appelé avec un scheduledAt, il réserve l'envoi pour cet instant — même endpoint, même clé, mêmes permissions.
json
{"success": true, "data": {"campaignId": "…", "status": "send_requested"}}

Programmation : un champ facultatif, même endpoint

Pas de corps du tout, un corps vide ou un corps sans scheduledAt : tout cela signifie la même chose, envoyer maintenant. Les appelants écrits avant l'ajout de ce champ n'ont rien à changer.
bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
  -d '{"scheduledAt": "2026-08-12T07:00:00Z"}' \
  "https://www.agentsmail.io/api/v1/campaigns/$CAMPAIGN_ID/send"
json
{"success": true, "data": {"campaignId": "…", "status": "scheduled"}}
status distingue les deux cas : send_requested pour un envoi qui démarre maintenant, scheduled pour un envoi réservé pour plus tard. La campagne passe en scheduled, et GET /api/v1/campaigns/{campaignId} renvoie l'instant réellement enregistré — à relire une fois, car la programmation est conservée à la minute près et les secondes que vous transmettez sont ignorées.
Une date sans fuseau horaire est refusée, jamais interprétée comme UTC. 2026-08-12T09:00:00 répond 400 : l'API ne devine pas un décalage que vous n'avez pas écrit, car une erreur de devinette enverrait avec une heure ou deux d'écart sans que rien dans la requête ne le montre. Écrivez 2026-08-12T07:00:00Z, ou 2026-08-12T09:00:00+02:00 — les deux désignent le même instant. Un instant passé, ou à moins de quelques minutes, est refusé de la même façon.
La programmation concerne un draft, et la pause/reprise restent dans l'application. Une campagne déjà scheduled répond 400 — elle n'est pas reprogrammée sur place. Mettre en pause ou reprendre une programmation se fait depuis l'application, sur l'écran de la campagne ; aucun endpoint ne l'expose. Réservez l'heure que vous voulez vraiment.
État de la campagnePOST /sendavec scheduledAt
draft202 — l'envoi est demandé202 — la campagne est programmée
scheduled202 — elle part maintenant400 — seul un brouillon peut être programmé
paused409 — reprenez-la dans l'application409
sending409 — un envoi est déjà en cours409
sent409 — elle est déjà partie409
failed409 — pas dans un état permettant l'envoi409
aucun lien de désabonnement dans le contenu400 — rien n'est émis400 — rien n'est programmé
inconnue, ou d'une autre organisation404404
Le contenu est rendu avant toute émission. C'est exactement la même vérification que POST /api/v1/render : une campagne dont le HTML ne porte pas {{unsubscribeUrl}} répond 400 et aucun envoi n'est créé. Sans ce lien, chaque envoi échouerait plus tard pour une raison que l'API ne vous montre jamais. Corrigez le modèle, recréez la campagne, puis envoyez.
Appeler l'envoi deux fois n'envoie jamais deux fois. Une campagne déjà partie répond 409 et aucun second envoi n'est lancé — réessayer après un délai d'attente dépassé est sans risque. Pour renvoyer le même contenu, créez une nouvelle campagne.
Interrogez ensuite GET /api/v1/campaigns/{campaignId} : status passe de draft → sending → sent, et progress se remplit au fil de l'envoi. Il n'y a aucun webhook à attendre.

Autorisation

Rôle dans l'organisationCet endpoint
OWNERAutorisé
ADMINAutorisé
MEMBERRefusé — 403
Une clé porte le rôle que son créateur détient dans cette organisation — jamais un rôle sur AgentsMail lui-même. Voir Clés d'API.

Corps de la requête

ChampTypeObligatoireDescription
scheduledAtstringnonInstant ISO 8601 avec un décalage explicite. Omis, la campagne part maintenant

Exemple

bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" \
  "https://www.agentsmail.io/api/v1/campaigns/$CAMPAIGN_ID/send"

Réponse

  • 202 Accepted — l'envoi est mis en file d'attente ; suivez-le sur la campagne.
  • 401 Unauthorized — clé absente ou invalide, ou son propriétaire a quitté l'organisation.
  • 403 Forbidden — le propriétaire de la clé est member de l'organisation, pas admin.
  • 404 Not Found — aucune ressource de ce type, ou elle appartient à une autre organisation. L'API ne confirme jamais l'existence d'un id à un appelant qui n'y a pas droit.
  • 429 Too Many Requests — plus de 120 requêtes en une minute pour cette clé.

Champs de la réponse

ChampTypeDescription
successbooleanIndique si l'opération a réussi
data.statusstringsend_requested quand elle part maintenant, scheduled quand une date a été fournie

Exemple de réponse

json
{
  "success": true,
  "data": {
    "status": "subscribed"
  }
}

Recette pour agent

Un envoi est asynchrone : l'appel revient dès que le départ est accepté, pas quand les e-mails sont partis. Interrogez la campagne pour le suivre — et arrêtez d'interroger quand l'envoi est désactivé, sinon la boucle ne se termine jamais.
js
await fetch(`${base}/campaigns/${campaignId}/send`, {method: 'POST', headers})

for (;;) {
  const {data} = await (
    await fetch(`${base}/campaigns/${campaignId}`, {headers})
  ).json()

  if (!data.sendingEnabled) throw new Error('sending is paused: polling would never end')
  if (data.status === 'sent' || data.status === 'failed') return data
  await new Promise((resolve) => setTimeout(resolve, 5000))
}
N'appelez jamais cet endpoint sans l'accord humain explicite pour cette campagne précise. L'accord pour un envoi ne couvre jamais le suivant.

Voir aussi