> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qwairy.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks sortants

> Recevez les événements de rapport hebdomadaire et d’export prêt sous forme de requêtes POST JSON signées sur votre endpoint.

Une équipe Enterprise peut envoyer les notifications prises en charge vers son propre endpoint, sous forme d’événements JSON signés. Lorsque l’envoi par webhook est activé, Qwairy n’envoie pas l’email correspondant.

<Note>
  Les webhooks sortants font partie des [Agences](/fr/agencies/introduction), une fonctionnalité **Enterprise**. Leurs réglages sont réservés au rôle **OWNER** (Propriétaire).
</Note>

## Événements

<CardGroup cols={2}>
  <Card title="report.weekly" icon="chart-line">
    Le rapport hebdomadaire d’un workspace.
  </Card>

  <Card title="export.ready" icon="file-arrow-down">
    Un export de données est terminé et prêt à être téléchargé.
  </Card>
</CardGroup>

Le bouton **Envoyer un événement de test** envoie aussi un événement `webhook.test` pour valider votre endpoint avant d’activer l’envoi.

## Configurer l’envoi

<Steps>
  <Step title="Ouvrez Marque blanche">
    Ouvrez **Gestion de l’équipe > Marque blanche** et repérez la carte **Webhooks sortants**.
  </Step>

  <Step title="Ajoutez l’URL de votre endpoint">
    Saisissez une URL `https` publique et enregistrez-la. Les adresses privées et les URL `http` sont refusées. Un **secret de signature** est généré et affiché une seule fois : copiez-le et conservez-le.
  </Step>

  <Step title="Envoyez un événement de test">
    Cliquez sur **Envoyer un événement de test** pour vérifier que Qwairy atteint votre endpoint et que votre contrôle de signature passe.
  </Step>

  <Step title="Activez l’envoi">
    Activez **Envoyer par webhook**. Les événements ci-dessus partent alors vers votre endpoint au lieu d’être envoyés par email.
  </Step>
</Steps>

Vous pouvez renouveler le secret à tout moment avec **Régénérer le secret** (la nouvelle valeur n’est affichée qu’une fois), et supprimer le webhook pour revenir à l’email.

## Contenu

Chaque requête est un `POST` avec une enveloppe JSON :

```json theme={null}
{
  "event": "export.ready",
  "id": "8b40e94f-79f4-40cc-8d38-bde11ef0d8d9",
  "createdAt": "2026-06-18T09:00:00.000Z",
  "team": { "id": "team_abc123", "name": "Acme" },
  "data": {
    "exportId": "cmg1x0c9r0001l204qk1nv8dz",
    "exportType": "answers",
    "rowCount": 842
  }
}
```

L’objet `data` dépend de l’événement. Traitez-le comme évolutif : de nouveaux champs peuvent apparaître, ignorez donc ceux que vous n’utilisez pas au lieu de rejeter le contenu.

## En-têtes

| En-tête | Valeur |
| - | - |
| `X-Qwairy-Event` | Nom de l’événement, par exemple `export.ready` |
| `X-Qwairy-Timestamp` | Heure Unix (en secondes) de la signature de la requête |
| `X-Qwairy-Signature` | HMAC `sha256=<hex>` de la requête |

## Vérifier la signature

La signature est un HMAC-SHA256 calculé avec votre secret de signature. Son entrée est `<timestamp>.<body>`, avec les octets bruts de la requête avant l’analyse JSON.

```js theme={null}
import crypto from 'crypto';

function isValidQwairyWebhook(req, secret) {
  const signature = req.headers['x-qwairy-signature']; // "sha256=<hex>"
  const timestamp = req.headers['x-qwairy-timestamp'];

  // Reject stale requests to prevent replay (e.g. older than 5 minutes).
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected =
    'sha256=' +
    crypto
      .createHmac('sha256', secret)
      .update(`${timestamp}.${req.rawBody}`)
      .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}
```

<Warning>
  Vérifiez la signature de chaque requête et rejetez tout échec. Utilisez une comparaison à temps constant, et rejetez les horodatages hors d’une courte fenêtre pour bloquer les rejeux.
</Warning>

## Comportement de l’envoi

* Qwairy attend une réponse `2xx`. Les réponses non `2xx`, les délais dépassés et les redirections comptent comme des échecs.
* Un envoi de rapport hebdomadaire en échec est retenté à l’exécution planifiée suivante ; l’email correspondant n’est **pas** envoyé à sa place.
* L’événement d’export prêt n’est envoyé qu’une fois : en cas d’échec, l’export reste disponible dans l’espace **Exports** de votre workspace.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.