---
title: "Alertes d'échec de paiement Stripe : litiges, refus et webhooks morts"
description: "Stripe vous prévient par e-mail des litiges et paiements échoués. Comment transformer les événements webhook Stripe en push, alerte urgente ou appel."
date: 2026-09-11
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - Stripe
  - paiements
  - webhooks
  - litiges
  - SaaS
  - alerting
---

# Alertes d'échec de paiement Stripe : litiges, refus et webhooks morts

Stripe sait déjà quand un litige est ouvert, quand un paiement d'abonnement échoue ou quand un virement est rejeté. Il vous le dit par e-mail. Pour obtenir quelque chose de plus sonore, enregistrez dans Stripe un second endpoint webhook pointant vers l'URL d'un canal Echobell, abonnez-le à une poignée de types d'événements et choisissez le type de notification en fonction de l'échéance attachée à chacun. Les litiges et les alertes précoces de fraude ont un chrono qui tourne ; un renouvellement échoué, en général, non.

Ce guide couvre les événements Stripe qui méritent de vous interrompre, la façon de brancher Stripe sur Echobell en cinq minutes environ, les champs de modèle qui existent réellement sur chaque objet, et le compromis que vous acceptez en sautant la vérification de signature.

## Les événements qui méritent vraiment de vous interrompre

L'alerting de paiement échoue toujours de la même manière : quelqu'un s'abonne à `payment_intent.succeeded` parce que c'est agréable, le téléphone vibre quarante fois par jour, et six semaines plus tard une notification de litige défile sans être lue. Partez plutôt de l'échéance. Si rater l'événement pendant huit heures ne coûte rien, il n'a pas besoin de vous atteindre en huit secondes.

| Événement | Pourquoi c'est important | Type conseillé |
| --- | --- | --- |
| `charge.dispute.created` | Vous avez une fenêtre limitée pour répondre — [généralement 7 à 21 jours selon le réseau de cartes](https://docs.stripe.com/disputes/responding). Manquée, elle vaut défaite automatique. | Appel |
| `radar.early_fraud_warning.created` | L'émetteur de la carte a signalé à Stripe qu'un paiement pourrait être frauduleux. Rembourser avant que cela ne devienne un litige formel est l'action qui vous reste, et la fenêtre est courte. | Appel |
| `payout.failed` | L'argent encaissé par Stripe n'arrive pas sur votre compte. Tout ce qui en dépend — salaires, calcul de runway — est désormais faux. | Appel |
| `invoice.payment_failed` | Churn involontaire. Cela se résout souvent tout seul, donc un appel est excessif, mais les plus gros comptes méritent un coup d'œil le jour même. | Urgent |
| `customer.subscription.deleted` | Churn volontaire. Bon à savoir aujourd'hui, pas de quoi vous réveiller. | Normal |
| `payment_intent.succeeded` | Rien n'est cassé. C'est précisément l'événement qui vous entraîne à ignorer les cinq autres. | Rien |

Ces niveaux correspondent aux trois [types de notification](/fr/docs/notification) d'Echobell : **Normal** est un push ordinaire, **Urgent** traverse la plupart des modes de concentration, et **Appel** se présente comme un appel entrant et sonne donc malgré Ne pas déranger. Chaque abonné choisit son niveau canal par canal : votre cofondatrice peut prendre les litiges en appel pendant qu'un collègue du support les reçoit en push.

## Ce qu'il vous faut

- Un compte Stripe avec accès à l'[onglet Webhooks de Workbench](https://dashboard.stripe.com/webhooks)
- Echobell installé ([App Store](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-stripe-payment-failure-alerts-fr&mt=8) / [Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid))
- Cinq minutes. Pas de serveur, pas de déploiement, pas de code — sauf si vous voulez la vérification de signature, qui fait l'objet de la dernière section.

## Étape 1 — Un canal par type d'événement

La tentation est de créer un unique canal « Stripe » et d'y envoyer tout. Ne le faites pas. Le modèle de corps et le lien vers le tableau de bord diffèrent entre un litige, une facture et un virement, parce que chacun transporte un objet différent — et tout l'intérêt du montage est que la notification vous dise ce qui s'est passé sans rien ouvrir.

Créez un canal nommé d'après l'événement : `Stripe Disputes`. Écrivez les modèles de titre et de corps pour qu'ils se lisent d'un trait sur l'écran verrouillé :

```
Title: 🔴 Dispute opened — {{data.object.reason}}
Body: Amount: {{data.object.amount}} {{data.object.currency}}
Charge: {{data.object.charge}}
Status: {{data.object.status}}
```

Réglez le modèle de lien dans les paramètres avancés pour que l'enregistrement de notification ouvre la bonne page :

```
https://dashboard.stripe.com/disputes/{{data.object.id}}
```

Abonnez-vous ensuite avec le type **Appel** et copiez l'URL du webhook depuis la vue détaillée du canal. Elle ressemble à `https://hook.echobell.one/t/<channel-token>`.

<Callout type="info">Activez **POST Only** dans les paramètres avancés du canal. Stripe envoie toujours en POST, et cet interrupteur fait que coller l'URL dans une fenêtre de chat ou un onglet de navigateur ne peut plus déclencher une fausse alerte de litige.</Callout>

## Étape 2 — Pointer Stripe vers le canal

Dans le tableau de bord Stripe, ouvrez l'[onglet Webhooks](https://dashboard.stripe.com/webhooks) et créez une destination d'événements :

<Steps>

<Step>

Cliquez sur **Create an event destination**, sélectionnez **Your account** et laissez la version de l'API sur la valeur par défaut de votre compte.

</Step>

<Step>

Sélectionnez exactement un type d'événement — `charge.dispute.created` pour ce canal. Le conseil de Stripe lui-même est de [ne s'abonner qu'aux événements dont votre intégration a besoin](https://docs.stripe.com/webhooks) ; ici, cela garde aussi le modèle honnête, puisque chaque payload reçu a la même forme.

</Step>

<Step>

Choisissez **Webhook endpoint** comme type de destination et collez l'URL du canal Echobell.

</Step>

<Step>

Enregistrez, puis utilisez **Send test event** — ou `stripe trigger charge.dispute.created` depuis la CLI — et vérifiez que le téléphone sonne.

</Step>

</Steps>

Répétez pour chaque canal créé. Stripe autorise jusqu'à 16 endpoints webhook par compte, largement de quoi en avoir un par niveau d'alerte.

## Étape 3 — Ce qui arrive réellement

Stripe poste l'[objet Event](https://docs.stripe.com/api/events/object) en JSON. Echobell lit le corps tel quel : chaque champ est donc adressable dans les modèles et les conditions avec la notation par points :

```json
{
  "id": "evt_1P...",
  "type": "charge.dispute.created",
  "livemode": true,
  "created": 1757548800,
  "data": {
    "object": {
      "id": "dp_1P...",
      "amount": 4900,
      "currency": "usd",
      "reason": "fraudulent",
      "status": "needs_response",
      "charge": "ch_3P...",
      "evidence_details": { "due_by": 1759449600 }
    }
  }
}
```

Trois choses surprennent dans ce payload :

**Les montants sont des entiers dans la plus petite unité monétaire.** Un `amount` de `4900` vaut 49,00 $. Les modèles Echobell interpolent et comparent les valeurs mais ne font pas d'arithmétique : `{{data.object.amount}}` affiche donc `4900`. Soit vous l'étiquetez honnêtement (`Amount: 4900 (cents)`), soit vous utilisez le relais de la dernière section pour diviser par 100 avant l'envoi.

**Les horodatages sont en secondes Unix.** `{{data.object.evidence_details.due_by}}` s'affiche `1759449600`, pas sous forme de date. Si l'existence de l'échéance compte plus que l'heure exacte, retirez-la du modèle — la page du litige l'affiche — et laissez le modèle de lien faire le travail.

**Les noms de champs diffèrent selon l'objet.** Un litige a `amount` ; une facture a `amount_due`, `customer_email`, `attempt_count` et `hosted_invoice_url` ; un virement a `failure_message` et `arrival_date` ; une alerte précoce de fraude a `fraud_type`, `actionable` et `charge` sous forme de simple ID texte. Une variable absente s'affiche comme chaîne vide plutôt que comme erreur : un modèle copié du mauvais canal échoue donc en silence. C'est la raison pratique du principe « un canal par type d'événement ».

## Étape 4 — Filtrer par conditions, pas par volonté

Les [conditions](/fr/docs/conditions) de canal utilisent la même syntaxe d'expressions que les modèles, sans les accolades, et s'exécutent avant toute livraison.

Celle à mettre sur chaque canal Stripe :

```
livemode == true
```

Le trafic en mode test — vos propres `stripe trigger`, un collègue qui bricole dans un bac à sable — n'atteint plus votre téléphone. Ajoutez-la après avoir vérifié que le câblage fonctionne, pas avant.

Pour le canal des factures échouées, un seuil tient les petits comptes à l'écart de vos soirées :

```
livemode == true && data.object.amount_due > 20000
```

À lire « plus de 200 $ », en centimes. Et si vous préférez voir les relances réellement bloquées plutôt que chaque premier échec :

```
livemode == true && data.object.attempt_count > 1
```

Si vous avez malgré tout dirigé un endpoint portant plusieurs types d'événements vers un seul canal, les conditions les redécoupent :

```
type == "charge.dispute.created" || type == "payout.failed"
```

## Étape 5 — Garder le chemin d'alerte hors de ce qui casse

Voici la partie qui vaut plus que les modèles.

Votre endpoint webhook de production est l'endroit où se fait la livraison du service : il ouvre les accès, écrit en base, envoie le reçu. C'est donc aussi l'endpoint qui tombe quand votre application tombe. Quand cela arrive, Stripe [réessaie jusqu'à trois jours avec un backoff exponentiel](https://docs.stripe.com/webhooks) et vous envoie un e-mail — et un e-mail sur des webhooks non livrés ressemble à tous les autres e-mails Stripe, ce qui explique qu'on le retrouve le lundi.

La mort silencieuse d'un webhook a des causes banales. Stripe traite une redirection `3xx` comme un échec : un endpoint qui se met à rediriger `http` vers `https` ou à ajouter une barre oblique finale cesse de recevoir des événements. Il exige TLS 1.2 ou supérieur : un certificat expiré ou mal configuré suffit. Un `403` renvoyé par une règle WAF ajoutée la semaine dernière aussi.

Un second endpoint pointé droit sur Echobell ne partage rien de tout cela. C'est une autre URL sur un autre hôte avec un autre certificat, et elle continue de sonner pendant que votre application est à terre. La règle se généralise : *le chemin qui vous dit que quelque chose est cassé ne devrait pas passer par la chose cassée.*

Vous voulez tout de même voir l'échec de votre propre endpoint. Consultez l'onglet **Event deliveries** dans Workbench quand quelque chose cloche — il affiche `Delivered`, `Pending` et `Failed` par événement, avec le statut HTTP de chaque tentative. Stripe permet de renvoyer un événement jusqu'à 15 jours depuis le tableau de bord, ou 30 jours avec `stripe events resend` en CLI : un trou repéré en quinze jours est donc rattrapable.

<Callout type="warn">L'URL de canal Echobell est un identifiant porteur : quiconque la détient peut déclencher le canal. Pointer Stripe directement dessus signifie que personne ne vérifie l'en-tête `Stripe-Signature` : une URL divulguée est une machine à fausses alertes, pas une fuite de données. Gardez-la hors des dépôts et des captures d'écran, utilisez **Reset Token** si elle s'échappe, et lisez la section suivante si ce compromis vous gêne.</Callout>

## Optionnel — Vérifier d'abord la signature

Si vous voulez que la signature Stripe soit réellement vérifiée et les montants formatés comme de l'argent, placez un petit relais devant. Ce Cloudflare Worker vérifie l'événement, renvoie `200` immédiatement comme Stripe le demande, et envoie à Echobell un payload à plat :

```js
import Stripe from "stripe";

export default {
  async fetch(request, env, ctx) {
    const stripe = new Stripe(env.STRIPE_SECRET_KEY);
    const body = await request.text();

    let event;
    try {
      event = await stripe.webhooks.constructEventAsync(
        body,
        request.headers.get("stripe-signature"),
        env.STRIPE_WEBHOOK_SECRET,
      );
    } catch {
      return new Response("invalid signature", { status: 400 });
    }

    const invoice = event.data.object;
    ctx.waitUntil(
      fetch(env.ECHOBELL_HOOK_URL, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          customer: invoice.customer_email || invoice.customer,
          amount: (invoice.amount_due / 100).toFixed(2),
          currency: invoice.currency.toUpperCase(),
          attempt: invoice.attempt_count,
          externalLink: invoice.hosted_invoice_url,
        }),
      }),
    );

    return new Response("ok", { status: 200 });
  },
};
```

Le modèle de l'autre côté devient bien plus agréable, puisque la mise en forme s'est faite dans le code :

```
Title: 💳 Payment failed — {{currency}} {{amount}}
Body: Customer: {{customer}}
Attempt #{{attempt}}
```

`externalLink` est une variable spéciale : sans modèle de lien défini, Echobell l'utilise pour le lien de l'enregistrement de notification, et la facture hébergée est alors à une tape de distance.

Notez la forme du compromis : vous venez d'ajouter une infrastructure qui peut elle-même tomber, ce contre quoi l'étape 5 met précisément en garde. Un compromis raisonnable consiste à vérifier les signatures sur le canal à fort volume, là où de fausses alertes seraient pénibles, et à laisser le canal des litiges branché en direct, là où une sonnerie parasite coûte un regard perplexe et une sonnerie manquée coûte le montant contesté.

## Ce que ce montage ne fournit pas

- **Ni tour d'astreinte ni escalade.** Toutes les personnes abonnées à un canal d'appel sonnent en même temps. C'est une qualité à quatre et un problème à quarante ; à quarante, il vous faut une plateforme d'incidents.
- **Pas de déduplication.** Stripe [ne garantit pas l'ordre des événements](https://docs.stripe.com/webhooks) et peut livrer le même plusieurs fois. Deux sonneries pour un litige, c'est possible.
- **Pas d'accusé de réception.** Rien n'enregistre qu'un humain l'a vu, et rien n'escalade vers une deuxième personne si personne ne réagit.
- **Pas d'alerte « les paiements se sont arrêtés ».** Stripe émet des événements quand les choses arrivent, jamais quand elles cessent. Si votre tunnel de paiement casse, aucun événement ne part. Celle-là exige une tâche planifiée de votre côté qui ping un canal quand le nombre de paiements de la dernière heure est nul — un [homme mort à base de cron](/fr/blog/cron-job-failure-alerts).

## Dépannage

**L'événement de test affiche `200` dans Stripe mais aucune notification n'arrive.** Echobell répond `200` avec un corps JSON même sans livrer — regardez le corps de la réponse dans l'onglet Event deliveries. `success: false` avec un jeton de longueur valide signifie que le jeton du canal est faux. Si `success` vaut `true`, la cause probable est une condition : `livemode == true` bloque tous les événements de test, par conception.

**Stripe signale `405 Method Not Allowed`.** Le canal a POST Only activé et quelque chose a envoyé un GET. Stripe poste toujours : c'est donc un aperçu de lien ou un onglet de navigateur, pas Stripe.

**La notification arrive avec des champs vides.** Le modèle vise le mauvais objet — `{{data.object.amount}}` sur un canal de factures, où le champ s'appelle `amount_due`. Envoyez un vrai événement, ouvrez-le dans le tableau de bord et lisez le JSON.

**Les livraisons échouent après des semaines de fonctionnement.** Vérifiez le certificat et toute redirection devant l'URL. Avec une URL de canal utilisée en direct, c'est rare ; avec un relais que vous avez déployé, c'est le suspect habituel.

## Questions fréquentes

### Stripe peut-il m'appeler quand un litige s'ouvre ?

Pas tout seul. Stripe vous prévient par e-mail, dans le tableau de bord, via l'événement `charge.dispute.created`, et par push si vous utilisez l'application Stripe Dashboard. Pour une vraie sonnerie, routez cet événement vers un canal dont le type d'abonnement est **Appel**.

### Faut-il écrire du code pour relier Stripe à Echobell ?

Non. Stripe poste du JSON vers n'importe quelle URL HTTPS publique, et une URL de canal Echobell en est une. Le code n'est nécessaire que si vous voulez vérifier l'en-tête `Stripe-Signature` ou reformater les montants.

### Est-il sûr de donner à Stripe une URL de webhook tierce ?

C'est un arbitrage assumé. Le payload envoyé par Stripe contient des métadonnées client et paiement, et Echobell ne conserve pas durablement les payloads bruts — la notification rendue vit sur votre appareil. Ce que vous abandonnez, c'est la vérification de signature : qui connaît l'URL peut vous envoyer un faux convaincant. Traitez-la comme une clé d'API et utilisez le relais pour tout ce que vous préférez vérifier.

### Pourquoi mon alerte affiche-t-elle 4900 au lieu de 49,00 $ ?

Stripe envoie les montants en entiers dans la plus petite unité monétaire, et les modèles Echobell ne font pas d'arithmétique. Indiquez l'unité dans le modèle, ou divisez par 100 dans un relais avant l'envoi.

### Comment empêcher les événements de test de me réveiller ?

Ajoutez la condition `livemode == true` au canal. Stripe marque tous les événements de bac à sable et de `stripe trigger` en `livemode: false`.

### Mon cofondateur peut-il recevoir les mêmes alertes sans payer un siège ?

Oui. Partagez le lien du canal ; chaque abonné choisit son type de notification. L'un peut prendre les litiges en appel pendant que l'autre les reçoit en push normal, et il n'y a pas de tarification par siège pour les abonnés.

### Faut-il alerter sur les paiements réussis ?

Brièvement seulement, et uniquement tant que l'activité est assez petite pour que chacun reste un événement. Dès que la notification de paiement réussi devient une routine, elle commence à éroder votre réaction à celles qui comptent — le mécanisme central de la [fatigue d'alerte](/fr/blog/fix-alert-fatigue-developer-guide).

## Conclusion

Tout le montage tient en une destination d'événements Stripe par canal Echobell, une condition `livemode == true`, et la discipline de réserver le niveau appel aux événements munis d'un chrono. Les litiges et les alertes précoces de fraude en ont un. Un renouvellement échoué sur une offre à 9 $, non — et faire semblant du contraire est exactement la façon dont on finit par dormir pendant celui qui en avait un.

[Téléchargez Echobell pour iPhone](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-stripe-payment-failure-alerts-fr&mt=8) ou [récupérez-le sur Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid), créez d'abord le canal des litiges, et lancez un `stripe trigger charge.dispute.created` avant de confier quoi que ce soit de sérieux à ce chemin.

---

## À lire aussi

- [Documentation d'intégration webhook](/fr/docs/webhook)
- [Référence des conditions de canal](/fr/docs/conditions)
- [Guide du développeur contre la fatigue d'alerte](/fr/blog/fix-alert-fatigue-developer-guide)
- [Alertes d'échec de tâches cron](/fr/blog/cron-job-failure-alerts)
- [Notifications webhook Zapier sur votre téléphone](/fr/blog/zapier-webhook-notifications-to-phone)
