Comment fonctionne la facturation — ce que Stripe prend en charge, et l'attribution des droits par webhook

Cet article fait partie du cours Les bases de l'informatique, qui construit depuis zéro les connaissances informatiques pratiques indispensables pour programmer et faire du vibe coding.
Les données de carte s'arrêtent chez le prestataire de paiement et ne passent jamais par ton propre serveur. Des schémas montrent pourquoi c'est la notification webhook qui justifie l'ouverture des fonctionnalités payantes.

Cet article porte sur le fonctionnement de la facturation.

Il se divise en deux parties : empêcher les données de carte d'atteindre ton propre serveur, et répercuter le résultat du paiement dans ta propre application.

Où circulent les données de carte, et ce qui justifie l'attribution des droits
Saisie de la cartepar l'utilisateurLe prestatairela reçoitLe résultat arriveen notificationLe numéro de cartes'arrête icimy-app enregistreles droits
La branche du haut est celle des données de carte : elle s'arrête à l'intérieur du prestataire de paiement. La branche du bas est celle du résultat du paiement, et my-app ne regarde qu'elle pour ouvrir les fonctionnalités payantes.

Le numéro de carte s'arrête sur la branche du haut et n'atteint jamais my-app.

Seule la notification qui arrive par la branche du bas justifie l'ouverture des fonctionnalités payantes.

La réception du numéro de carte comme les échanges avec l'émetteur de la carte se font du côté du prestataire de paiement, et il ne reste à my-app que l'inscription du résultat dans un enregistrement.

C'est le prestataire de paiement qui reçoit les données de carte, pas ton propre serveur

Le traitement d'un paiement nécessite le numéro de la carte, sa date d'expiration et son code de sécurité.

La norme que respectent les entreprises qui manipulent des données de carte est le PCI DSS (Payment Card Industry Data Security Standard), et un prestataire de paiement (payment service provider) est un service externe qui prend en charge les paiements par carte à ta place.

Stripe et PayPal sont les prestataires de paiement les plus connus.

L'endroit où tu places les champs de saisie détermine par où circule le numéro de carte.

Emplacement des champsPar où circule le numéroConcerné par le PCI DSS
Reçu et stocké par my-appmy-app et le prestatairemy-app est concerné aussi
Reçu par my-app puis transmismy-app et le prestatairemy-app est concerné aussi
Page du prestataire de paiementLe prestataire uniquementPérimètre minimal pour my-app

Seule la troisième ligne laisse le numéro de carte en dehors du serveur de my-app.

Dans ce cas, my-app ne conserve que la valeur qui identifie le paiement, alors que les deux premières lignes laissent derrière elles le numéro de carte lui-même ou une trace des échanges.

Même transmis sans être stocké, le numéro passe par ton propre serveur, et dès qu'il y passe, my-app entre lui aussi dans le périmètre du PCI DSS.

Pour réduire au minimum la zone que my-app doit protéger, tu confies les champs de saisie eux-mêmes au prestataire de paiement.

Lors d'un seul paiement, jusqu'où va chaque information
Un paiement (pay_88)
Reste chez le prestataire de paiement
  • Numéro de carte, date d'expiration, code de sécurité
  • Trace des échanges avec l'émetteur de la carte
Arrive à my-app
  • La valeur qui identifie le paiement, pay_88
  • Le montant, et si le paiement a abouti
  • À quel utilisateur appartient le paiement (u_1024)
Le cadre extérieur est un paiement, pay_88. Les données de carte restent uniquement dans le cadre du haut. my-app ne détient que le fait que le paiement a abouti et la valeur qui l'identifie.

Le numéro de carte ne passe pas par my-app

Si tu ne reçois jamais toi-même le numéro de carte, la responsabilité de le protéger ne retombe pas non plus sur toi.

Que tu le stockes ou que tu le transmettes aussitôt, la même responsabilité s'applique dès qu'il passe par ton propre serveur : tu confies donc les champs de saisie eux-mêmes au prestataire de paiement, et seul le fait que le paiement a abouti arrive jusqu'à my-app.

Le paiement se termine sur une page de paiement hébergée sur le domaine du prestataire

Une page de paiement hébergée (hosted checkout page ; page de paiement préparée par le prestataire de paiement et affichée sur son propre domaine) place l'écran de saisie lui-même ailleurs, pour que les données de carte ne passent jamais par ton propre serveur.

Le fait d'emmener l'utilisateur vers une page d'un autre domaine est une redirection (redirect).

À la deuxième étape, tu transmets le montant et l'adresse de retour, et le prestataire de paiement renvoie l'URL d'une page de paiement dédiée à ce paiement.

Cet échange se fait en appelant une API web, et tu y joins une clé d'API.

Les deux domaines ouverts dans le navigateur pendant un paiement
Navigateur
Domaine de my-app
  • La page d'inscription à l'offre payante
  • /thanks, ouverte après le paiement
Domaine du prestataire
  • La page de paiement où le numéro de carte est saisi
  • my-app ne voit pas ce que contient cette page
Le cadre extérieur est le navigateur de l'utilisateur. Le cadre du haut est la page de my-app, celui du bas la page du prestataire de paiement ; une redirection fait passer du haut vers le bas, puis revenir en haut.

La page de paiement est aussi proposée sous forme de cadre placé dans la page de my-app.

L'apparence change, mais les valeurs saisies aboutissent au même endroit.

Deux façons de la placer : ce qui change et ce qui ne change pas
Passage versune autre pageURL = domainedu prestataireAprès paiement,retour à /thanksCadre placédans la pageURL = domainede my-appAprès paiement,même pageDans les deux casLe numéro va auprestatairemy-app ne reçoitque le fait du paiement
Les deux lignes du haut sont les différences entre les deux placements, la ligne du bas ce qui reste identique dans les deux cas. De gauche à droite : le placement, l'URL affichée dans le navigateur, puis ce qui se passe après le paiement.

C'est le prestataire de paiement qui fournit la page de paiement

La page où le numéro de carte est saisi appartient au prestataire de paiement, pas à my-app.

Une redirection emmène l'utilisateur vers cette page, et après le paiement il revient sur /thanks ; même si tu la places sous forme de cadre dans ta propre page, les valeurs saisies aboutissent au même endroit.

Ce qui justifie l'attribution des droits, c'est la notification webhook, pas la page de retour

C'est my-app, et non le prestataire de paiement, qui décide si les fonctionnalités payantes peuvent être affichées, et cet enregistrement est le droit d'accès (entitlement ; enregistrement de l'étendue des fonctionnalités accessibles à un utilisateur ayant payé).

Le simple retour de l'écran de l'utilisateur sur /thanks n'indique pas à my-app que le paiement a abouti.

Distingue deux chemins dans ce qui se passe après un paiement.

Après la fin d'un paiement, les deux chemins qui mènent à my-app
Le navigateurpasse sur /thanksLa page affichela confirmationS'il est fermé,rien n'arriveLe paiement finitsur la pageLe serveur appelle/webhookNotificationavec signatureRenvoyée pendantune durée fixée
Deux chemins partent d'un même paiement. Celui du haut passe par le navigateur et peut s'interrompre en route ; celui du bas va de serveur à serveur et continue jusqu'à recevoir un succès.

Le chemin du haut s'arrête net si l'utilisateur ferme son navigateur juste après avoir payé.

Celui du bas va de serveur à serveur : si la notification n'arrive pas, elle est renvoyée un nombre de fois et pendant une durée fixés à l'avance.

Selon celui que tu retiens comme justification, les mêmes trois personnes n'obtiennent pas les mêmes droits.

Ce qui est arrivé à l'utilisateurSi tu juges sur /thanksSi tu juges sur /webhook
A payé et ouvert /thanksDroits attribuésDroits attribués
A payé puis fermé aussitôtAucun droit attribuéDroits attribués
A ouvert /thanks sans payerDroits attribuésAucun droit attribué

Si tu juges sur /thanks, celui qui a fermé son navigateur n'obtient rien, tandis que celui qui n'a pas payé obtient des droits.

La seule chose sur laquelle tu fondes l'attribution des droits est la notification du chemin du bas.

Dans un paiement, si tu appliques deux fois la même notification, la période d'accès est prolongée deux fois.

Enregistre la valeur qui identifie chaque notification, et ne modifie pas les droits à la deuxième arrivée de la même notification.

Comment my-app trie ce qui arrive sur /webhook
Notification à lasignature invalidePremière arrivéede evt_7evt_7renvoyée/webhookla reçoitRejetée ; droitsinchangésDroits attribués,evt_7 enregistréDéjà enregistrée,donc rien à faire
Les trois éléments de gauche arrivent tous sur le même /webhook. Ils sont reçus ensemble au centre, puis la signature et la valeur qui identifie la notification les répartissent entre les trois cas de droite.

Une notification dont la signature ne correspond pas est rejetée sans modifier les droits.

La seule différence entre les deux autres est de savoir si cette notification a déjà été appliquée.

Les trois types d'enregistrements conservés dans la base de données de my-app
La base de données de my-app
Enregistrement utilisateur
  • La valeur qui identifie l'utilisateur, u_1024
  • Le hachage du mot de passe
Enregistrement des droits
  • Type d'offre (paid)
  • Date de fin d'accès
  • À quel utilisateur il appartient (u_1024)
Enregistrement des notifications
  • La valeur qui identifie la notification, evt_7
  • La date d'application
Le cadre extérieur est la base de données de my-app. L'enregistrement des droits, au centre, contient le type d'offre et la date de fin d'accès. L'enregistrement des notifications, en bas, évite qu'une notification renvoyée soit appliquée deux fois.

Même si tu masques le bouton payant sur la page, ce code parvient quand même à l'appareil de l'utilisateur.

Vérifier les droits côté serveur à chaque fois, c'est la même autorisation que celle présentée dans Le fonctionnement de la connexion.

Le numéro de carte s'arrête dans le cadre du milieu et n'entre pas dans celui de droite.

Les droits sont attribués à l'arrivée de la notification de la flèche 2, pas au retour du navigateur de l'utilisateur.

C'est une notification du serveur qui signale le paiement

Ce qui signale qu'un paiement a abouti, ce n'est pas la page sur laquelle l'utilisateur revient, mais la notification qui arrive depuis le serveur du prestataire de paiement.

Tu vérifies la signature de ce qui arrive, tu laisses les droits inchangés si la notification a déjà été appliquée, tu inscris le résultat dans ta propre base de données, et c'est à partir de là que tu décides d'afficher ou non les fonctionnalités payantes.

Avec un abonnement, une notification arrive à chaque période et les droits changent

Un contrat facturé au mois ou à l'année est un abonnement (subscription ; contrat dont le paiement se répète automatiquement à intervalle fixé).

Entre un paiement unique et un abonnement, ce qui change, c'est le nombre de notifications
Type de paiementPaiement uniqueNotification uniqueLa date de finne change pasAbonnementArrive à chaquepériodeLa date de finest repoussée
La colonne de gauche est le type de paiement. Le chemin du haut est le paiement unique, celui du bas l'abonnement. Dans les deux cas, c'est la notification webhook qui justifie les droits ; ce qui diffère, c'est le nombre d'arrivées et la date de fin.

Un paiement qui se répète ne réussit pas forcément à chaque fois.

Sur la ligne de l'échec, le prestataire de paiement laisse passer quelques jours et réessaie le prélèvement.

C'est my-app qui décide de maintenir l'accès pendant ce temps ou de le couper aussitôt.

Ce qui permet de vérifier avant la mise en ligne est le mode test (test mode ; état préparé par le prestataire de paiement pour vérifier le fonctionnement sans déclencher de prélèvement réel).

Les clés d'API sont distinctes pour le test et la production : tu passes de l'une à l'autre par la valeur d'une variable d'environnement.

Définis la notification qui retire les droits avant la mise en ligne

Avec un abonnement, un paiement a lieu à chaque échéance de période, et une notification arrive à chaque fois.

Si tu ne traites que la notification qui attribue l'accès, les utilisateurs dont les paiements se sont arrêtés le conservent : décide donc, pour chaque notification reçue, l'attribution, la prolongation et le retrait, puis déroule tout le parcours en mode test avant la mise en ligne.

QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

Question 1Quand tu encaisses des paiements via un prestataire de paiement, par où circulent les données de carte ?

Question 2Sur quoi t'appuies-tu pour conclure qu'un paiement a abouti et attribuer des droits à l'utilisateur ?

Question 3Quand une notification signalant l'échec d'un paiement arrive pour un prélèvement récurrent, que fait ton application ?