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

# Webhooks

> Recevez des notifications en temps réel pour les paiements, les payouts et plus encore.

Les webhooks permettent à Kori de notifier votre serveur lorsqu'un événement survient —
et surtout lorsqu'un encaissement asynchrone est confirmé. Enregistrez vos endpoints avec
le scope `webhooks` (tableau de bord → **Portail développeur → Webhooks**, ou via l'API).

## Enregistrer un endpoint

```bash theme={null}
curl -X POST https://api.kori.ml/merchant/api/webhooks \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://exemple.com/webhooks/kori",
    "events": ["payment_received", "payout_completed"]
  }'
```

La réponse contient un `secret`, affiché **une seule fois** : conservez-le en lieu sûr,
il sert à vérifier les signatures. Vous pouvez enregistrer jusqu'à **5 endpoints** par
compte marchand.

## Événements

| Événement           | Déclenché quand                                   |
| ------------------- | ------------------------------------------------- |
| `payment_received`  | Un encaissement (`/pay`) est confirmé et crédité  |
| `payout_completed`  | Un payout a abouti                                |
| `payout_failed`     | Un payout n'a pas pu être finalisé                |
| `bulk_pay_done`     | Un lot de paiements en masse a fini d'être traité |
| `payment_link_used` | Un lien de paiement a reçu un paiement réussi     |
| `team_login`        | Un membre de l'équipe s'est connecté              |
| `api_key_created`   | Une nouvelle clé API a été créée                  |
| `security_alert`    | Un événement lié à la sécurité s'est produit      |

## Format de livraison

Kori envoie une requête `POST` avec un corps JSON et ces en-têtes :

| En-tête            | Description                                                                                   |
| ------------------ | --------------------------------------------------------------------------------------------- |
| `X-Kori-Signature` | HMAC-SHA256 du corps brut de la requête, avec votre secret de webhook comme clé (hexadécimal) |
| `X-Kori-Event`     | Le nom de l'événement                                                                         |

```json Corps theme={null}
{
  "event": "payment_received",
  "data": { "transaction_id": 88213, "reference": "commande_1024", "amount": 5000 },
  "timestamp": "2026-08-08T12:00:00.000Z",
  "merchant_id": 42
}
```

Répondez rapidement avec un statut `2xx`. Toute réponse autre que 2xx compte comme un
échec.

## Vérifier la signature

Vérifiez toujours `X-Kori-Signature` avant de faire confiance à un contenu. Calculez le
HMAC sur le corps **brut** (et non sur un objet re-sérialisé) avec votre secret de
webhook.

<CodeGroup>
  ```javascript Node.js theme={null}
  const crypto = require("crypto");

  function verifierSignatureKori(corpsBrut, signature, secret) {
    const attendu = crypto
      .createHmac("sha256", secret)
      .update(corpsBrut)
      .digest("hex");
    return crypto.timingSafeEqual(
      Buffer.from(attendu),
      Buffer.from(signature)
    );
  }

  // Express : récupérer le corps brut
  app.post(
    "/webhooks/kori",
    express.raw({ type: "application/json" }),
    (req, res) => {
      const ok = verifierSignatureKori(
        req.body,                       // Buffer du corps brut
        req.header("X-Kori-Signature"),
        process.env.KORI_WEBHOOK_SECRET
      );
      if (!ok) return res.status(400).send("signature invalide");

      const evenement = JSON.parse(req.body.toString());
      // traiter evenement.event / evenement.data ...
      res.sendStatus(200);
    }
  );
  ```

  ```python Python theme={null}
  import hmac, hashlib

  def verifier_signature_kori(corps_brut: bytes, signature: str, secret: str) -> bool:
      attendu = hmac.new(secret.encode(), corps_brut, hashlib.sha256).hexdigest()
      return hmac.compare_digest(attendu, signature)
  ```
</CodeGroup>

<Warning>
  Vérifiez la signature sur les **octets bruts** du corps de la requête. Convertir en JSON
  puis re-sérialiser modifie les espaces et l'ordre des clés, ce qui invalide la signature.
</Warning>

## Relances et désactivation automatique

Chaque livraison échouée incrémente un compteur d'échecs. Après plusieurs échecs
consécutifs, l'endpoint est automatiquement **désactivé** (`is_active: false`). Corrigez
votre endpoint puis réactivez-le avec `PUT /merchant/api/webhooks/{id}`.

## Tester un endpoint

Envoyez un événement `test` pour vérifier que votre gestionnaire fonctionne :

```bash theme={null}
curl -X POST https://api.kori.ml/merchant/api/webhooks/{id}/test \
  -H "Authorization: Bearer <token>"
```
