Webhooks & événements
Chaque étape de la vie d'un e-mail transactionnel produit un événement, consultable par
GET /smtp/statistics/events et envoyé aux webhooks abonnés à cet événement.
| Événement (abonnement) | Valeur event reçue |
Origine |
|---|---|---|
sent / request |
request |
e-mail accepté pour envoi, un événement par destinataire |
delivered |
delivered |
remise confirmée par le serveur destinataire |
deferred |
deferred |
remise différée |
softBounce / hardBounce |
soft_bounce / hard_bounce |
rejet temporaire / définitif |
opened |
opened |
pixel d'ouverture, à chaque ouverture |
uniqueOpened |
unique_opened |
première ouverture du message par ce destinataire |
click |
click |
lien suivi |
blocked |
blocked |
destinataire ou domaine bloqué, l'e-mail ne part pas vers lui |
spam, invalid et unsubscribed sont acceptés comme abonnements pour rester compatibles
avec Brevo, mais aucun événement de ce type n'est produit aujourd'hui.
Un rejet définitif ajoute le destinataire aux contacts bloqués : les envois suivants vers
cette adresse produisent blocked.
Gérer les webhooks
| Méthode et chemin | Réponse |
|---|---|
POST /webhooks |
201 avec { "id": 12 } |
GET /webhooks?type=transactional&sort=desc |
200 avec { "webhooks": [...] } |
GET /webhooks/{webhookId} |
200 avec le webhook |
PUT /webhooks/{webhookId} |
204, seuls les champs fournis changent |
DELETE /webhooks/{webhookId} |
204 |
Un identifiant inconnu renvoie 404 (document_not_found).
Créer un webhook
curl -s -X POST "$BREVO_BASE/webhooks" -H "api-key: $BREVO_API_KEY" \
-H "content-type: application/json" -d '{
"url": "https://ma-boutique.fr/webhooks/brevo",
"description": "Suivi des commandes",
"events": ["delivered", "hardBounce", "opened", "click"],
"type": "transactional",
"auth": { "type": "bearer", "token": "un-secret" },
"headers": [{ "key": "X-Source", "value": "inklura" }]
}'
| Champ | Détail |
|---|---|
url |
requis, http ou https, doit viser une adresse publique |
events |
tableau non vide ; sans events, le webhook reçoit tous les événements transactionnels |
type |
transactional par défaut ; marketing et inbound sont acceptés mais ne reçoivent aucun envoi |
channel |
email (défaut) ou sms ; seuls les webhooks email reçoivent les événements |
auth |
{ "type": "bearer", "token" } envoie Authorization: Bearer … ; { "type": "basic", "username", "password" } envoie Authorization: Basic … |
headers |
tableau de { "key", "value" } ajoutés à chaque appel |
batched |
true : la charge utile arrive dans un tableau (un événement par appel) |
description, domain |
texte libre, renvoyé par GET |
Erreurs : 400 missing_parameter sans url, 400 invalid_parameter pour une URL invalide ou
privée, un events vide ou un nom d'événement inconnu pour le type.
Charge utile
Chaque événement est envoyé en POST JSON, avec l'en-tête User-Agent: Brevo-Webhooks/1.0.
{
"event": "click",
"email": "client@example.com",
"id": 7,
"date": "2026-09-24 14:26:05",
"ts": 1790259965,
"message-id": "<202609241426.12345678901@smtp-relay.mailin.fr>",
"ts_event": 1790259965,
"ts_epoch": 1790259965000,
"subject": "Commande 1042 confirmée",
"tag": "order-confirmation",
"tags": ["order-confirmation"],
"template_id": 3,
"sender_email": "boutique@ma-boutique.fr",
"link": "https://ma-boutique.fr/suivi/1042"
}
id est l'identifiant du webhook, date est en UTC. Selon l'événement s'ajoutent reason
(motif d'un rejet ou d'un blocage) et sending_ip. Sans tag, tag vaut "" et tags est
absent ; template_id n'apparaît que pour un envoi par modèle.
Réponse et nouvelles tentatives
Répondez en 2xx dans les 10 secondes. Un délai dépassé, une erreur réseau, un 429 ou un
5xx relance l'appel, jusqu'à trois tentatives au total (environ 1 s puis 4 s d'écart). Une
autre réponse 4xx arrête les tentatives. Les redirections sont suivies (trois au plus) et
chaque adresse doit rester publique.
Historique
POST /webhooks/export produit un CSV des événements transactionnels et répond 202 avec
{ "processId": 42 }.
| Champ | Détail |
|---|---|
notifyURL |
requis, adresse publique |
days |
7 par défaut, ignoré si startDate est fourni |
startDate, endDate |
AAAA-MM-JJ |
email, messageId |
filtres facultatifs |
sort |
desc (défaut) ou asc |
notifyURL reçoit en POST { "processId", "status": "completed", "export_url" }. Le lien
est aussi renvoyé par GET /processes/{processId}. Le CSV est séparé par ; (colonnes
date, event, email, messageId, subject, tag, reason, link) et la colonne
event reprend les noms de GET /smtp/statistics/events (requests, clicks,
hardBounces…). L'export compte au plus 100 000 lignes.