Aller au contenu
Docs

Référence

Le format exact des requêtes de webhook d’Emailit, de la méthode et des en-têtes au tableau JSON d’événements, ainsi que l’ordre, les doublons et la manière de répondre.

Mis à jour le 1 oct. 2026

Cette page décrit ce qui arrive sur votre endpoint : la requête HTTP, ses en-têtes, le corps JSON et la réponse qu’attend Emailit. Consultez-la lorsque vous écrivez ou déboguez un gestionnaire de webhook.

Requête

Propriété Valeur
Méthode POST
Corps Un tableau JSON de 1 à 100 événements, compact (sans espaces superflus)
Timeout 30 secondes
Redirections Non suivies. Une réponse 3xx compte comme un échec.
Simultanéité Une requête à la fois par webhook. Les lots sont envoyés les uns après les autres.
Latence Emailit recherche de nouveaux événements toutes les quelques secondes : la plupart des événements arrivent en quelques secondes.
HTTP
POST /webhooks/emailit HTTP/1.1
Host: acme.com
Content-Type: application/json
User-Agent: Emailit-Webhooks/2.0
X-Emailit-Signature: 7242b580f77ec488f8ac21b57f092e3db61a431694f13074c7b4c85a4dd04be3
X-Emailit-Timestamp: 1790846045

En-têtes

En-tête Description
Content-Type Toujours application/json.
User-Agent Toujours Emailit-Webhooks/2.0.
X-Emailit-Signature HMAC-SHA256 encodé en hexadécimal de {timestamp}.{raw body}, calculé avec le secret complet du webhook (whsec_ compris) comme clé. Consultez Signature des requêtes.
X-Emailit-Timestamp Horodatage Unix, en secondes, de la signature de la requête par Emailit. Chaque tentative, nouvelles tentatives comprises, est signée de nouveau avec un nouvel horodatage.

Corps

Le corps est toujours un tableau JSON, même lorsqu’il ne contient qu’un seul événement. Chaque élément a cette structure :

Champ Type Description
event_id chaîne L’ID de l’événement, qui commence par evt_. Un même événement conserve le même ID d’une tentative à l’autre. Les événements de test commencent par evt_test_.
type chaîne Le type d’événement, par exemple email.delivered.
object objet La ressource concernée par l’événement.
data objet Contient de nouveau object. data.object et l’object de premier niveau sont identiques ; lisez celui que vous préférez.

Les champs de object dépendent du type. Les événements de statut d’e-mail décrivent l’e-mail ; email.clicked et email.loaded décrivent le clic ou le chargement et imbriquent l’e-mail ; les événements de ressource comme contact.created décrivent la ressource.

Exemple de lot

Cette requête contient deux événements : une livraison et un clic ultérieur sur un lien du même e-mail.

JSON
[
  {
    "event_id": "evt_2xGk7Nq1VbD5sR8tLmW3eYhC6aP",
    "type": "email.delivered",
    "object": {
      "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
      "object": "email",
      "from": "billing@acme.com",
      "to": "ada@example.com",
      "subject": "Your receipt #1042",
      "status": "delivered",
      "meta": { "order_id": "1042" },
      "updated_at": "2026-10-01T09:14:03.512000+00:00",
      "created_at": "2026-10-01T09:14:01.207000+00:00"
    },
    "data": {
      "object": {
        "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
        "object": "email",
        "from": "billing@acme.com",
        "to": "ada@example.com",
        "subject": "Your receipt #1042",
        "status": "delivered",
        "meta": { "order_id": "1042" },
        "updated_at": "2026-10-01T09:14:03.512000+00:00",
        "created_at": "2026-10-01T09:14:01.207000+00:00"
      }
    }
  },
  {
    "event_id": "evt_2xGkC8w2TnF4yR7bMqL1sVdJ6pE",
    "type": "email.clicked",
    "object": {
      "id": "click_2xGkC7v5PmD3xQ9aLnK2rUcH8oW",
      "object": "click",
      "email_id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
      "email": {
        "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
        "rcpt_to": "ada@example.com",
        "mail_from": "billing@acme.com",
        "subject": "Your receipt #1042",
        "created_at": "2026-10-01T09:14:01.207000+00:00",
        "campaign": null,
        "meta": { "order_id": "1042" }
      },
      "link": {
        "id": "link_2xGk7Mb6QwE1zS8cNpT4vXfK3gB",
        "url": "https://acme.com/orders/1042"
      },
      "contact": { "id": "con_2xFh3Ka9LmP2nR6tVwB8cDqY5sZ", "email": "ada@example.com" },
      "ip_address": "203.0.113.24",
      "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
      "created_at": "2026-10-01T09:20:47.884000+00:00"
    },
    "data": {
      "object": {
        "id": "click_2xGkC7v5PmD3xQ9aLnK2rUcH8oW",
        "object": "click",
        "email_id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
        "email": {
          "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
          "rcpt_to": "ada@example.com",
          "mail_from": "billing@acme.com",
          "subject": "Your receipt #1042",
          "created_at": "2026-10-01T09:14:01.207000+00:00",
          "campaign": null,
          "meta": { "order_id": "1042" }
        },
        "link": {
          "id": "link_2xGk7Mb6QwE1zS8cNpT4vXfK3gB",
          "url": "https://acme.com/orders/1042"
        },
        "contact": { "id": "con_2xFh3Ka9LmP2nR6tVwB8cDqY5sZ", "email": "ada@example.com" },
        "ip_address": "203.0.113.24",
        "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
        "created_at": "2026-10-01T09:20:47.884000+00:00"
      }
    }
  }
]

Les horodatages sont au format ISO 8601 en UTC. meta contient les métadonnées que vous avez associées à l’envoi, ou null. contact vaut null lorsque le destinataire ne fait pas partie de vos contacts, et campaign vaut null pour les e-mails envoyés via l’API et SMTP.

Ordre

Au sein d’une requête, les événements sont classés du plus ancien au plus récent. D’une requête à l’autre, l’ordre n’est pas garanti : un lot en échec est réessayé plus tard alors que des événements plus récents sont peut-être déjà arrivés, et une relance manuelle peut renvoyer d’anciens événements après des nouveaux.

Ne vous fiez pas à l’ordre d’arrivée. Pour les événements d’e-mail, utilisez les champs status et updated_at de l’e-mail et conservez l’état le plus avancé que vous avez vu (par exemple, n’écrasez pas clicked avec un delivered tardif). En cas de doute, récupérez l’état actuel avec Récupérer un e-mail.

Doublons

Un même événement peut arriver plusieurs fois :

  • Lorsque votre endpoint dépasse le timeout ou renvoie une erreur après avoir traité une partie d’un lot, le lot entier est réessayé, y compris les événements que vous avez déjà traités.
  • Lorsque vous utilisez Retry failed ou relancez une requête individuelle.

Enregistrez chaque event_id traité, avec une contrainte d’unicité, et ignorez les événements déjà vus.

Répondre

Votre réponse Résultat
N’importe quel 2xx dans les 30 secondes Chaque événement du lot est marqué Delivered. Le corps de la réponse est ignoré.
3xx, 4xx ou 5xx Le lot est en échec et fait l’objet d’une nouvelle tentative.
Aucune réponse dans les 30 secondes, erreur de connexion, erreur TLS Le lot est en échec et fait l’objet d’une nouvelle tentative. Le tableau de bord affiche le code de statut 0.

Pour les requêtes en échec, Emailit conserve les 2 000 premiers caractères du corps de votre réponse. Vous pouvez le consulter dans l’onglet Requests du webhook : renvoyer un court message d’erreur facilite donc le débogage.

Recommandations :

  • Vérifiez, puis accusez réception rapidement. Contrôlez la signature, placez les événements dans une file d’attente ou une table, et renvoyez 200. Effectuez les traitements lents, comme les appels à d’autres API, dans une tâche en arrière-plan.
  • Renvoyez 2xx pour les événements que vous ignorez. Sinon, ils sont réessayés pendant des jours.
  • Renvoyez 401 ou 403 pour une signature invalide. La requête est réessayée comme pour tout échec, ce qui vous laisse le temps de corriger un secret mal configuré.

Pour le calendrier des nouvelles tentatives et ce qui se passe lorsqu’un endpoint continue d’échouer, consultez Nouvelles tentatives et échecs.

Cette page vous a-t-elle été utile ?

Merci pour votre retour.

Merci, nous lisons chaque message.