---
term: 'Webhooks'
seoTitle: 'Webhooks expliqués : sécurité HMAC, retries, idempotence'
headline: 'Que sont les webhooks ?'
slug: webhooks
category: backend-compute
shortDefinition: 'Un webhook est un callback HTTP automatisé : quand un événement survient, un système envoie le payload en POST à une URL enregistrée par un autre système.'
relatedTerms:
  - event-driven-architecture
  - websockets-real-time-sync
  - cloud-code-serverless-functions
  - pub-sub-pattern
contrastsWith:
  - websockets-real-time-sync
aboutTerms:
  - 'Webhook Endpoint'
  - 'HMAC Signature Verification'
  - 'At-Least-Once Delivery'
faq:
  - question: "Qu'est-ce qu'un webhook en termes simples ?"
    answer: "Un message HTTP automatique qu'un système envoie à un autre à l'instant où quelque chose se produit — une sonnette au lieu d'aller vérifier la porte sans arrêt. Vous donnez une URL à un fournisseur ; quand l'événement se déclenche, il y envoie les données de l'événement en POST. Le terme date de 2007 : \"user-defined HTTP callbacks\"."
  - question: 'Quelle est la différence entre un webhook et une API ?'
    answer: "La direction et l'initiative. Une API est pilotée par les requêtes — le client demande, le serveur répond. Un webhook est piloté par les événements — le serveur pousse quand quelque chose se produit, sans qu'on le lui demande. Un webhook est en réalité un pattern construit sur des API, et la plupart des intégrations réelles utilisent les deux : des webhooks pour apprendre les changements, des appels d'API pour agir dessus."
  - question: 'Quelle est la différence entre webhooks et polling ?'
    answer: "Le polling demande à intervalle fixe et entend surtout \"rien de nouveau\" — une mesure sur une grande plateforme d'automatisation est restée célèbre pour avoir constaté qu'environ 98 % des polls ne renvoient aucune donnée nouvelle. Les webhooks inversent la logique : zéro requête au repos, livraison immédiate au changement. Le polling survit comme filet de réconciliation sous les webhooks, pas comme leur rival."
  - question: 'Comment recevoir un webhook ?'
    answer: "Exposez un endpoint HTTPS qui accepte POST, enregistrez son URL auprès du fournisseur et sélectionnez les événements voulus. Dans le handler : vérifiez la signature, renvoyez un 2xx en quelques secondes et faites le vrai traitement en asynchrone. Testez avec un outil de capture avant de câbler la logique de production."
  - question: 'Les webhooks sont-ils sûrs ?'
    answer: "Pas par défaut — l'endpoint est une URL publique sur laquelle n'importe qui peut faire un POST. La défense standard est une signature HMAC : le fournisseur signe chaque payload avec un secret partagé, et vous recalculez sur le corps brut et comparez en temps constant, en rejetant les timestamps périmés pour bloquer les rejeux. HTTPS toujours ; les listes d'IP autorisées en complément."
  - question: 'Que se passe-t-il si mon endpoint est hors service ?'
    answer: "Les bons fournisseurs réessaient avec un backoff exponentiel, souvent pendant des heures ou des jours — c'est pourquoi la livraison est at-least-once et les doublons sont normaux. Des événements peuvent quand même se perdre au-delà de la fenêtre de retry, donc les intégrations critiques réconcilient avec des polls périodiques de l'API plutôt que de se fier aux seuls webhooks."
  - question: 'Comment gérer les livraisons de webhooks en double ?'
    answer: "Dédupliquez sur l'ID unique de l'événement : enregistrez les ID traités et ignorez les répétitions, en conservant l'enregistrement au moins aussi longtemps que la fenêtre de retry du fournisseur. Livraison at-least-once plus handler idempotent égale, en pratique, un traitement exactly-once — la moitié du contrat de fiabilité qui revient au récepteur."
  - question: 'Quelle est la différence entre un webhook et un WebSocket ?'
    answer: "Un webhook est une notification HTTP sans état, à sens unique, de serveur à serveur ; un WebSocket est une connexion persistante et bidirectionnelle, conçue pour le temps réel côté client comme le chat et les dashboards en direct. Un serveur prévient un serveur : webhook. Un serveur diffuse vers des interfaces utilisateur : WebSocket."
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'webhooks.fyi — webhook best practices'
    url: 'https://webhooks.fyi/'
  - name: 'W3C WebSub Recommendation'
    url: 'https://www.w3.org/TR/websub/'
  - name: 'REST Hooks — resthooks.org'
    url: 'https://github.com/zapier/resthooks'
  - name: 'OWASP SSRF Prevention Cheat Sheet'
    url: 'https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html'
cta:
  title: 'Des webhooks dans les deux sens'
  text: "Sur Back4app, un trigger afterSave est un webhook sortant et une Cloud Function un récepteur prêt à l'emploi — vérifiez la signature, écrivez dans votre base de données et laissez les Live Queries pousser le résultat vers chaque écran."
  linkText: 'Commencez gratuitement'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-09-09'
translationKey: webhooks
---

**Un webhook est un callback HTTP automatisé : quand un événement survient, un système envoie le payload en POST à une URL enregistrée par un autre système.** Le terme — forgé en 2007 sous la forme "user-defined HTTP callbacks" — nomme l'inversion qui compte : au lieu que votre système demande sans cesse si quelque chose a changé, l'autre système prévient le vôtre à l'instant où cela arrive. C'est du push construit avec les pièces les plus simples du web : une URL HTTPS, un POST, un corps JSON et un accusé de réception 2xx.

## Points clés

| Question | Réponse |
| --- | --- |
| Le mécanisme | Enregistrer une URL → l'événement se déclenche → le fournisseur envoie le payload en POST → vous renvoyez 2xx |
| vs. une API | Les API répondent quand on leur demande ; les webhooks parlent quand quelque chose se produit |
| Le niveau de sécurité | HMAC sur le corps brut, comparaison en temps constant, fenêtre de timestamp |
| La vérité sur la livraison | At-least-once, sans ordre, avec retries — dédupliquez et réconciliez |
| Le mantra du récepteur | Vérifier · accuser réception vite · traiter en asynchrone · dédupliquer par ID d'événement |

## La livraison, de bout en bout

```text
CONFIG    le récepteur expose  https://api.example.com/hooks/payments
          et l'enregistre auprès du fournisseur, en choisissant événements + secret

ÉVÉNEMENT un paiement aboutit chez le fournisseur

LIVRAISON POST /hooks/payments
          webhook-id: evt_8fk2            ← clé de déduplication
          webhook-timestamp: 1767024900   ← garde anti-rejeu (dans la signature)
          webhook-signature: v1,d2Vio…    ← HMAC-SHA256(secret, id.timestamp.body)
          { "type": "charge.succeeded", "orderId": "o-1187" }

ACK       le récepteur vérifie la signature → 200 en quelques secondes → le travail tourne en async
RETRY     pas de 2xx ? backoff exponentiel pendant des heures/jours → les doublons sont NORMAUX
```

Les deux directions du pattern en code — un trigger de données comme émetteur, une Cloud Function comme récepteur, et le client qui se contente d'observer le résultat :

**JavaScript:**

```javascript
// JavaScript — Cloud Code (cloud/main.js): both directions of a webhook
// OUTGOING: any data change can notify an external system
Parse.Cloud.afterSave('Order', async (req) => {
  if (req.object.get('status') !== 'paid') return;
  await Parse.Cloud.httpRequest({
    method: 'POST',
    url: 'https://hooks.example.com/orders', // the receiver's registered URL
    headers: { 'Content-Type': 'application/json' },
    body: { event: 'order.paid', id: req.object.id },
  });
});

// INCOMING: a Cloud Function is a ready-made webhook receiver
Parse.Cloud.define('paymentWebhook', async (req) => {
  verifySignature(req.params, process.env.WEBHOOK_SECRET); // HMAC first
  await markOrderPaid(req.params.orderId); // write fast, work async
  return { received: true }; // 2xx before heavy processing
});
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// The client's side of a webhook: watch its effect in real time
// (payment platform → Cloud Function receiver → database → Live Query → UI)
final orderQuery = QueryBuilder<ParseObject>(ParseObject('Order'))
  ..whereEqualTo('objectId', orderId);
final sub = await LiveQuery().client.subscribe(orderQuery);
sub.on(LiveQueryEvent.update, (order) {
  if (order.get<String>('status') == 'paid') showReceipt();
});
// The webhook itself was handled server-side — clients just watch the data.
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// The client's side of a webhook: watch its effect in real time
// (payment platform → Cloud Function receiver → database → Live Query → UI)
let orderQuery = Order.query("objectId" == orderId)
let sub = try await orderQuery.subscribe()
sub.handleEvent { _, event in
    if case .updated(let order) = event, order.status == "paid" {
        showReceipt()
    }
}
// The webhook itself was handled server-side — clients just watch the data.
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// The client's side of a webhook: watch its effect in real time
// (payment platform → Cloud Function receiver → database → Live Query → UI)
val orderQuery = ParseQuery.getQuery<ParseObject>("Order")
orderQuery.whereEqualTo("objectId", orderId)
val sub = ParseLiveQueryClient.Factory.getClient().subscribe(orderQuery)
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, order ->
    if (order.getString("status") == "paid") showReceipt()
}
// The webhook itself was handled server-side — clients just watch the data.
```

## Webhooks vs. API vs. polling

| | Webhook | Appel d'API | Polling |
| --- | --- | --- | --- |
| Initiative | Le fournisseur pousse | Le consommateur demande | Le consommateur demande à intervalle fixe |
| Timing | À l'événement | À la demande | Au prochain intervalle |
| Trafic gaspillé | Aucun au repos | Aucun | ~98 % des polls ne trouvent rien |
| Direction | Notification à sens unique | Requête/réponse bidirectionnelle | Bidirectionnel, répété |
| Point fort | "Préviens-moi quand" | "Fais ceci / donne-moi cela" | Réconciliation, fournisseurs sans webhooks |

Le débat est largement faux : les intégrations matures utilisent les trois — les webhooks pour apprendre vite les changements, les appels d'[API](/glossary/fr/api/) pour récupérer l'état faisant foi et agir, et un poll lent de réconciliation comme filet sous le trapèze.

## La checklist du récepteur

La liste que la documentation de chaque fournisseur disperse et qu'aucune explication ne rassemble :

1. **Vérifiez le HMAC sur le corps brut** — avant le parsing ; du JSON resérialisé casse les signatures.
2. **Comparez en temps constant** — l'égalité de chaînes fuit par le timing ; utilisez le comparateur de votre bibliothèque de cryptographie.
3. **Appliquez la fenêtre de timestamp** — rejetez les livraisons de plus de ~5 minutes ; comme le timestamp est *dans* le contenu signé, un attaquant ne peut pas rejouer une vieille requête valablement signée avec une horloge fraîche.
4. **Renvoyez 2xx vite** — en quelques secondes, avant le travail lourd ; les handlers lents subissent un timeout et sont réessayés jusqu'à devenir des tempêtes de doublons.
5. **Traitez en asynchrone** — mettez en file, accusez réception, puis travaillez.
6. **Dédupliquez par ID d'événement** — avec une mémoire au moins aussi longue que la fenêtre de retry du fournisseur.
7. **Ne faites pas confiance au payload pour les actions critiques** — traitez le webhook comme une sonnette ; récupérez l'état courant depuis l'API du fournisseur avant d'expédier des marchandises ou d'accorder un accès.
8. **Journalisez les livraisons et alertez sur les échecs** — le silence est indiscernable d'un endpoint cassé.

Une note de développement local que les pages de définition sautent : `localhost` est inaccessible depuis Internet, donc le développement passe par un outil de tunnel qui prête une URL publique à votre machine, plus un outil de capture pour rejouer de vrais payloads.

## Sémantique de livraison, honnêtement

La livraison des webhooks est **at-least-once** : le fournisseur réessaie jusqu'à l'accusé de réception, donc les doublons sont une *caractéristique* de la fiabilité, pas un bug — la livraison exactly-once sur un réseau non fiable est formellement impossible, et l'équivalent pratique est at-least-once plus votre handler idempotent. **L'ordre n'est pas garanti** : retries et envois parallèles s'entremêlent, donc `updated` peut arriver avant `created` ; appliquez les événements par ID et version, ou récupérez l'état à nouveau. Et **les fenêtres de retry se terminent** : un endpoint en panne pendant un week-end peut manquer des événements définitivement, c'est pourquoi les intégrations critiques où l'argent est en jeu associent les webhooks à une réconciliation périodique — la [même discipline at-least-once](/glossary/fr/pattern-pub-sub/) que les brokers formalisent, arrivant par simple HTTP. La comparaison se généralise : un webhook est du push point à point vers une URL connue ; le [pub/sub](/glossary/fr/pattern-pub-sub/) ajoute un broker, des topics et du fan-out ; [WebSockets et SSE](/glossary/fr/sse-vs-websockets-vs-polling/) servent des *clients*, pas des serveurs. Les webhooks sont la réponse précisément quand deux systèmes qui ne partagent pas d'infrastructure doivent être informés des événements l'un de l'autre.

```mermaid
flowchart LR
  accTitle: Livraison de webhook avec retries et traitement asynchrone
  accDescr: Un événement chez le fournisseur est mis en file et envoyé en POST avec une signature HMAC à l'URL enregistrée du récepteur. Le récepteur vérifie la signature, accuse réception rapidement avec un 2xx et traite en asynchrone avec déduplication. Les livraisons échouées réintègrent la file de retry du fournisseur avec backoff exponentiel, et les échecs répétés partent dans un journal dead-letter.
  E["Un événement survient"] --> Q["File du fournisseur<br/>+ signature HMAC"]
  Q -->|"POST du payload"| R["Endpoint du récepteur"]
  R -->|"vérifie → 2xx vite"| A["Worker asynchrone<br/>déduplique par ID d'événement"]
  R -.->|"pas de 2xx"| RT["Retry avec backoff<br/>heures → jours"] --> Q
  RT -.->|"épuisé"| DL["Journal dead-letter<br/>+ alerte"]
  A --> DB[("Votre base de données")]
```

## Construire le côté émetteur

Émettre des webhooks de façon fiable est un petit système à part entière, et aucune page de classement ne l'esquisse : une **file par destination**, pour qu'un endpoint mort ne bloque pas les autres ; des **retries avec backoff exponentiel et jitter** ; un **magasin dead-letter** avec des outils de relivraison une fois les tentatives épuisées ; une **signature HMAC** avec des secrets par endpoint et leur rotation ; des **abonnements par type d'événement**, pour que les récepteurs choisissent ce qu'ils veulent ; et des **journaux de livraison** que vos clients peuvent lire, parce que "vous l'avez envoyé ?" est la première question de support. Un point de sécurité propre aux émetteurs : les récepteurs enregistrent des URL arbitraires, alors validez-les contre les plages d'adresses internes — un attaquant qui enregistre `http://10.0.0.5/admin` comme "endpoint de webhook", c'est de la [server-side request forgery](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html) déguisée en fonctionnalité d'intégration.

## Cas d'usage courants

- **Cycles de vie des paiements** — débits, remboursements et changements d'abonnement annoncés à votre backend au fil de leur règlement.
- **Déclencheurs CI/CD** — le câblage canonique du git push qui lance un build.
- **Automatisation entre apps** — outils de formulaires, plateformes de chat et CRM chaînés à travers les événements les uns des autres.
- **Notifications opérationnelles** — alertes de monitoring et mises à jour de livraison qui atterrissent dans les canaux de l'équipe.
- **Synchronisation de données** — maintenir à jour un miroir local d'un système partenaire sans faire du polling sur toute son API.

## Devriez-vous utiliser un webhook ? Matrice de décision

| Situation | Choisissez |
| --- | --- |
| Le système d'une autre entreprise doit notifier le vôtre | Les webhooks — le standard de l'interopérabilité |
| Vos services, votre infrastructure | Le [pub/sub](/glossary/fr/pattern-pub-sub/) — avec broker, buffer et fan-out |
| Navigateurs/apps ont besoin de mises à jour en direct | [WebSockets / live queries](/glossary/fr/websockets/) |
| Le fournisseur n'offre pas de webhooks | Le polling, poliment |
| De l'argent ou un accès dépend de l'événement | Webhook + vérifier-puis-récupérer + réconciliation |
| Vous êtes la plateforme qui émet les événements | Construisez le côté émetteur ci-dessus — ou ne promettez pas de fiabilité |

## Limites et trade-offs

- **La livraison est best-effort au-delà de la fenêtre de retry.** Les webhooks notifient ; ils ne garantissent pas. Les polls de réconciliation couvrent tout ce qui ne doit pas être manqué.
- **Le récepteur hérite d'un devoir d'uptime.** La disponibilité de votre endpoint conditionne désormais les événements de quelqu'un d'autre — déploiements, cold starts et timeouts deviennent tous des bugs d'intégration.
- **La sécurité est opt-in.** Un endpoint de webhook non vérifié est une API d'écriture non authentifiée ; la checklist HMAC fait la différence entre intégration et injection.
- **Le débogage s'étend sur deux entreprises.** Des journaux de livraison des deux côtés et des outils de rejeu, voilà ce qui transforme "ce n'est pas arrivé" d'un bras de fer en un diff.
- **Les payloads dérivent.** Les fournisseurs versionnent les schémas d'événements ; les consommateurs figés sur des formes exactes cassent en silence — parsez de façon défensive et ignorez les champs inconnus.

## Les webhooks sur Back4app

Back4app est une plateforme open-source de Backend as a Service (BaaS) qui combine une base de données gérée, des API REST et GraphQL générées automatiquement, l'authentification, le stockage de fichiers et des fonctions serverless avec Cloud Code. Les deux moitiés du pattern ne demandent qu'une seule fonction [Cloud Code](/glossary/fr/cloud-code-fonctions-serverless/), comme le montrent les onglets de code. **Sortant :** un trigger `afterSave` qui observe vos données appelle `Parse.Cloud.httpRequest` vers n'importe quelle URL enregistrée — votre app devient fournisseur de webhooks en écrivant la fonction, et les disciplines du côté émetteur (retry en cas d'échec, journal des livraisons) vivent dans le même fichier. **Entrant :** une Cloud Function exposée en HTTPS est un récepteur prêt à l'emploi — vérifiez le HMAC contre un secret dans la configuration côté serveur, écrivez le résultat dans la base de données, répondez vite — et la mise à jour se propage ensuite à chaque écran ouvert via les [Live Queries](/glossary/fr/live-queries-temps-reel/), bouclant la boucle qui va de l'événement d'une plateforme de paiement au reçu de l'utilisateur sans un serveur à faire tourner à aucune des deux étapes.
