# Webhooks

> Recevoir ventes, urgences et pauses de l'IA en direct — événements, signature HMAC, livraisons.

URL : https://docs.fanconvert.ai/fr/api/rest/webhooks

Recevez les événements sans interroger l'API : `POST /public/v1/webhooks` avec une adresse `https://` publique (port 443 ou 8443) et les événements voulus. La réponse donne **une seule fois** le secret de signature `whsec_…`.

Droits : `webhooks:write` (et `webhooks:read` pour lister et lire le journal), plus le droit de lecture de chaque événement.

| Événement | Quand | Droit de lecture exigé |
|---|---|---|
| `sale.created` | une vente (MYM, Telegram, OnlyFans, Fanvue) | `sales:read` (+ `telegram:read` pour Telegram) |
| `emergency.created` | une nouvelle urgence | `notifications:read` |
| `ai.paused` | l'IA mise en pause sur un fan, ou coupée pour une créatrice | `chatting:read` |
| `ping` | `POST /public/v1/webhooks/{id}/ping`, pour tester | — |

Un événement ne porte **que des identifiants et des montants**, jamais le nom d'un fan ni un message : lisez le détail avec votre clé.

```json
{
  "id": "evt_9b1c…",
  "type": "sale.created",
  "apiVersion": "v1-beta",
  "createdAt": "2026-11-07T12:30:00Z",
  "data": {"platform": "mym", "creatorId": "emma-demo", "saleId": "s_…",
           "conversationId": "123", "amountMinor": 1500, "currency": "EUR", "at": "…"}
}
```

## Vérifier la signature [#vérifier-la-signature]

En-tête `FanConvert-Signature: t=<secondes>,v1=<hex>` : calculez HMAC-SHA256 de `"<t>.<corps brut>"` avec votre secret, comparez en temps constant, refusez un `t` de plus de 5 minutes.

```python
import hashlib, hmac, time

def verifier(secret: str, entete: str, corps: bytes) -> bool:
    champs = dict(p.split("=", 1) for p in entete.split(","))
    if abs(time.time() - int(champs["t"])) > 300:
        return False
    attendu = hmac.new(secret.encode(), f"{champs['t']}.".encode() + corps,
                       hashlib.sha256).hexdigest()
    return hmac.compare_digest(attendu, champs["v1"])
```

## Livraison [#livraison]

- Répondez `2xx` en moins de 10 s. Sinon, nouvel essai après 1 min, 5 min, 30 min, 2 h et 6 h (six essais), puis `failed`.
- Les redirections ne sont jamais suivies.
- L'en-tête `FanConvert-Event-Id` permet d'ignorer un doublon.
- Le journal : `GET /public/v1/webhooks/{id}/deliveries`.
- Un webhook vit avec sa clé : clé révoquée ou expirée, il se désactive. `DELETE /public/v1/webhooks/{id}` le désactive (le journal reste).
- Les événements sont détectés toutes les 30 s environ ; à la création, rien du passé n'est rejoué.

Référence : [Webhooks](/fr/api/reference/webhooks).

