# Requêtes de webhook

> 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.

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](/fr/docs/webhooks/request-signature/). |
| `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](/fr/docs/webhooks/event-types/), 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](/fr/docs/api-reference/emails/get/).

## 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](/fr/docs/webhooks/retries-and-failures/).

## Voir aussi

  - [Signature des requêtes](/fr/docs/webhooks/request-signature/)
  - [Types d’événements](/fr/docs/webhooks/event-types/)

---
Source: https://emailit.com/fr/docs/webhooks/webhook-requests/
