Arrêtez de rembourser des paiements que vous n'auriez jamais dû encaisser
Le flux encaisser-puis-rembourser est partout, et il est presque toujours mauvais. Autorisez d'abord, faites vos vérifications, puis capturez. Voici la propriété qui le permet.
J’ai un jour livré un tunnel de paiement qui débitait la carte à l’instant où le client cliquait sur payer, puis validait la commande ensuite. Vérification du stock, validation de l’adresse, une heuristique antifraude, un appel de disponibilité à un tiers. Quand l’un de ces contrôles échouait, le code faisait la chose évidente : il remboursait le paiement.
Ça marchait. Ça générait aussi un filet régulier d’e-mails confus et agacés. “Pourquoi m’avez-vous débité 89 euros pour me rembourser trois jours plus tard ?” Pour le client, un débit suivi d’un remboursement ne se lit pas comme “nous avons détecté un problème”. Ça se lit comme “cette entreprise est douteuse et mon argent est bloqué pour une semaine”.
Le correctif tenait dans une propriété que j’ignorais depuis des années : capture_method: manual.
L’antipattern encaisser-puis-rembourser
Voici le flux que presque tous les tutoriels enseignent, et celui que j’avais livré :
const intent = await stripe.paymentIntents.create({
amount: 8900,
currency: 'eur',
payment_method: paymentMethodId,
confirm: true,
});
// l'argent a déjà quitté le compte du client
const order = await validateOrder(cart);
if (!order.ok) {
await stripe.refunds.create({ payment_intent: intent.id });
throw new Error('Validation de la commande échouée après encaissement');
}
Le problème, c’est le commentaire. Au moment où validateOrder s’exécute, l’argent est parti. Le débit a touché le relevé du client, votre relevé, et dans les cas transfrontaliers une conversion de devise. Si la validation échoue, vous n’annulez pas une erreur, vous émettez un second événement financier qui doit se régler sur son propre calendrier.
Cela a des coûts réels :
- Le client voit un débit puis un remboursement, à plusieurs jours d’intervalle, et perd confiance
- Les remboursements peuvent prendre 5 à 10 jours ouvrés pour réapparaître sur le relevé
- Vous ne récupérez pas toujours tous les frais, et les variations de change font que le montant remboursé peut différer du débit
- Une série de débits-puis-remboursements est exactement ce que les réseaux de cartes signalent comme un risque
Vous avez tout fait pour être honnête et ça paraît quand même louche. C’est le flux le problème, pas vos intentions.
Autoriser, puis capturer
Les cartes supportent depuis toujours un modèle en deux temps : l’autorisation place une empreinte sur les fonds sans les déplacer, et la capture déplace réellement l’argent. Les hôtels et les loueurs de voitures l’utilisent depuis toujours. L’empreinte reste sur la carte du client, l’argent ne bouge pas tant que vous ne le décidez pas, et si vous ne capturez jamais, l’empreinte expire simplement.
Stripe expose cela avec une seule propriété sur le PaymentIntent :
const intent = await stripe.paymentIntents.create({
amount: 8900,
currency: 'eur',
payment_method: paymentMethodId,
capture_method: 'manual',
confirm: true,
});
// les fonds sont AUTORISÉS, pas capturés. Rien n'a bougé.
const order = await validateOrder(cart);
if (order.ok) {
await stripe.paymentIntents.capture(intent.id);
} else {
await stripe.paymentIntents.cancel(intent.id);
}
cancel libère l’empreinte. Aucun débit n’est apparu, donc il n’y a aucun remboursement à expliquer. Le client voit une autorisation en attente qui disparaît discrètement, ce à quoi tout porteur de carte est habitué. Vous avez déplacé la logique métier risquée là où elle doit être : entre l’autorisation et la capture, tant que l’argent est encore réversible sans laisser de trace.
Ce que vous obtenez gratuitement
Une fois le paiement autorisé mais non capturé, plusieurs choses deviennent possibles que le flux débit-d’abord rend pénibles.
Capture partielle. Vous pouvez capturer moins que ce que vous avez autorisé. Autorisez 89 euros pour un panier, découvrez qu’un article est en rupture, capturez 64 euros et le reste de l’empreinte se libère automatiquement :
await stripe.paymentIntents.capture(intent.id, {
amount_to_capture: 6400,
});
Une vraie fenêtre de validation. Stripe conserve une autorisation de carte non capturée pendant environ 7 jours avant qu’elle n’expire d’elle-même. C’est largement suffisant pour une vérification de stock synchrone, et assez pour certains flux asynchrones. Si vous ne capturez jamais, vous n’avez jamais débité.
Une piste d’audit propre. “Autorisé, puis annulé” est une histoire cohérente dans vos journaux comme dans l’esprit du client. “Débité, puis remboursé” est deux événements à réconcilier, et c’est dans cette réconciliation que l’argent disparaît discrètement.
Ce n’est pas propre à Stripe
Le nom de la propriété change, mais tout prestataire de paiement sérieux expose le même modèle autoriser-puis-capturer. Si vous construisez quelque chose d’agnostique au prestataire, c’est le pattern à standardiser :
- Stripe :
capture_method: 'manual'sur le PaymentIntent, puispaymentIntents.capture()oupaymentIntents.cancel() - Adyen : configurez un délai de capture manuelle sur le compte ou la requête, puis appelez
/paymentspour autoriser et/payments/{id}/capturespour capturer - Braintree : passez
submitForSettlement: falseàtransaction.sale, puistransaction.submitForSettlement(id)plus tard - PayPal : créez la commande avec
intent: 'AUTHORIZE', puis capturez l’autorisation
Le vocabulaire diffère, la forme est identique : obtenir une empreinte, faire son travail, régler ou libérer.
Quand ne pas l’utiliser
La capture manuelle n’est pas sans compromis, et c’est le mauvais outil dans quelques cas.
- Biens numériques instantanés. Si vous livrez à l’instant où le paiement réussit et qu’il n’y a rien à valider, l’aller-retour supplémentaire n’apporte rien. Capturez immédiatement.
- Abonnements et facturation récurrente. Ils tournent sur leur propre flux de capture automatique. N’ajoutez pas la capture manuelle à un abonnement sans raison précise.
- Validation plus lente que l’empreinte. Si vos contrôles peuvent dépasser la fenêtre d’autorisation, l’empreinte risque d’expirer avant la capture. Accélérez les contrôles ou repensez le flux.
- Moyens de paiement non compatibles. Certains moyens de paiement hors carte ne proposent pas d’autorisation et de capture séparées. Vérifiez la compatibilité des moyens que vous acceptez avant de construire dessus.
La règle que je suis maintenant
S’il existe une logique métier qui peut échouer après que le client a payé mais avant que vous acceptiez de garder son argent, cette logique se place entre une autorisation et une capture. Pas avant un débit, et surtout pas après.
Le flux encaisser-puis-rembourser est le défaut de presque tous les exemples en ligne, et c’est précisément pour ça qu’il finit en production. Une seule propriété déplace le travail risqué du bon côté de l’argent, et les e-mails agacés s’arrêtent.
Si les frais de Stripe sont aussi un problème pour votre volume, voir Alternatives à Stripe en Europe pour des prestataires qui supportent le même modèle d’autorisation puis capture.