Stocker les données de paiement Stripe en base de donnée

Temps de lecture ~4 minutes

Il est difficile de savoir si les données de paiement Stripe doivent être stockées localement en base de donnée ou non. De nombreux développeurs se demandent quel type de données Stripe ils doivent enregistrer dans leur BDD. Ils peuvent même parfois être tentés de n’enregistrer aucune donnée localement et de seulement se baser sur des appels API Stripe.

Laissez-moi vous montrer comment nous traitons cette question chez NLP Cloud et pourquoi.

NLP Cloud est une API de traitement naturel du language (NLP) basée sur spaCy et HuggingFace Transformers afin de proposer de l’extraction d’entités (NER), analyse de sentiments, classification de texte, résumé de texte, génération de texte, et bien plus. Les clients sont prélevés mensuellement et les paiements sont gérés par Stripe. Il est important pour nous que l’API et le dashboard utilisateur soient rapides comment l’éclair. Nous voulons donc dépendre le moins possible d’appels à l’API de Stripe. Nous souhaitons par ailleurs ne pas trop dépendre d’une potentielle perte de donnée du côté de Stripe.

Scénario typique

Voici un scénario standard pour un service à abonnement comme le notre chez NLP Cloud :

  1. Un client s’inscrit sur votre site
  2. Vous enregistrez le client en BDD
  3. vous créez un client Stripe via l’API de Stripe
  4. Vous enregistrez l’ID client Stripe localement dans votre base

Vous ne pouvez pas vraiment faire mieux que cela.

Maintenant voilà la partie plus ardue.

Par exemple, il est probable que vous ayez besoin de garder une trace en local de l’abonnement Stripe de votre client, afin de lui donner accès à certaines fonctionnalités payantes, ou à plus de requêtes API, ou, s’il s’agit d’un utilisateur gratuit, de désactiver certaines fonctionnalités (par exemple). Certaines fois vous serez amené à mettre à jour un abonnement vous-même, mais d’autres fois ce sera à l’initiative de Stripe (par exemple dans le cas d’un paiement en échec plusieurs fois d’affilée, Stripe marquera l’abonnement comme canceled). Lorsqu’un abonnement est mis à jour par Stripe, ils vous le font savoir via un webhook. Si vous utilisez Stripe Portal, tout sera intégralement géré côté Stripe, et tout changement vous sera signalé via webhook.

Donc l’intégration Stripe est bi-directionnelle : parfois les modifications viennent de vous, parfois d’eux. Il est facile de finir avec des informations non synchronisées !

Considérations autour de la vitesse

On pourrait être tenté de déléguer autant d’information que possible à Stripe de façon à ce que Stripe soit la seule source de données. Dans une configuration de ce type, vous auriez besoin d’appeler l’API Stripe très fréquemment. C’est une mauvaise idée.

Par exemple, si vos données d’abonnement clients sont uniquement stockées chez Stripe, il vous faudra en premier effectuer un appel Stripe avant d’autoriser un client à accéder ou non à une fonctionnalité payante spécifique. Cela ajoute des millisecondes critiques au temps de réponse de votre site, ce qui n’est pas bon. Et si Stripe se met à ramer, votre site va se mettre à ramer aussi. Dans le cas d’une API, c’est tout simplement hors de question : vous ne pouvez pas ralentir un appel API parce que vous êtes dans l’attente d’une réponse de Stripe.

Considérations autour d’un plan de reprise d’activité

Déléguer les informations à Stripe sans copie des données en local est risqué. Même si Stripe est un acteur solide, vous ne serez jamais certain qu’ils ne risquent pas de perdre vos données.

Afin d’assurer une reprise d’activité en cas de potentiel incident, il est crucial de stocker les données des clients en local afin de pouvoir relancer le service quelque part ailleurs en cas d’incident grave, et ceci sans perdre une seule donnée d’abonnement client (ce qui serait un désastre).

Tout mettre en cache localement

La stratégie que nous suivons chez NLP Cloud est de tout mettre en cache localement. C’est plus simple qu’il n’y parait grace au fait que les SGBD modernes comme PostgreSQL savent facilement stocker le JSON sans presque aucun compromis en terme de performances.

En gros, voici ce que vous devrez faire si vous souhaitez suivre cette voie :

  1. Lorsque vous créez un client Stripe via leur API, sauvegardez la réponse JSON de Stripe au sein d’un champ JSON en BDD (avec PostgreSQL, utilisez le type JSONB)
  2. Lorsque vous créez un abonnement Stripe pour ce client, faite de même
  3. Lorsque vous souhaitez accéder aux informations de clients ou d’abonnements Stripe, contentez-vous de les chercher dans votre base de donnée

Voici un exemple d’INSERT dans un champ JSONB PostgreSQL :

CREATE TABLE customers (  
  id serial NOT NULL,
  stripe_customer jsonb
  stripe_subscription jsonb
);
INSERT INTO customers VALUES (1, '{id:1, ...}', '{id:1, ...}');

Et voici comment vous pouvez récupérer les données d’abonnement Stripe par exemple :

SELECT stripe_subscription->'id' AS id FROM customers;  

2 champs en BDD et c’est tout ! Nul besoin de créer toute une batterie de champs afin de stocker les nombreuses informations de clients et d’abonnements.

Rester synchro

Afin de vous assurer que votre cache local soit parfaitement synchronisé avec Stripe, vous devez correctement recevoir et traiter les webhooks de Stripe.

A chaque fois que vous recevez un webhook Stripe concernant un client ou un abonnement, mettez à jour les champs client et abonnement en BDD.

Si vous souhaitez être complètement tranquille, vous pouvez aussi vous préparer à un potentiel dysfonctionnement des webhooks. Dans ce cas, la meilleure stratégie est de pro-activement aller chercher les clients et les abonnements Stripe via l’API à intervalles réguliers, afin d’être certain de ne pas perdre d’infos.

Conclusion

Comme vous le voyez, il est relativement facile de mettre en place un système de cache Stripe qui soit simple et robuste. Cette stratégie épargne un temps de développement non négligeable; elle est rapide, sûre en cas de dysfonctionnement côté Stripe, et vous n’avez plus besoin de vous demander de quelles données Stripe vous avez besoin localement ou non.

J’espère que vous avez trouvé cela utile. Si vous avez des retours, ou si vous pensez à une meilleure stratégie, faites-le moi savoir !

Also available in English

Rate Limiting d'API avec Traefik, Docker, Go, et la mise en cache

Limiter l'utilisation de l'API en fonction d'une règle avancée de limitation du débit n'est pas si facile. Pour y parvenir derrière l'API NLP Cloud, nous utilisons une combinaison de Docker, Traefik (comme proxy inverse) et la mise en cache locale dans un script Go. Si cela est fait correctement, vous pouvez améliorer considérablement les performances de votre limitation de débit et étrangler correctement les demandes d'API sans sacrifier la vitesse des demandes. Continuer de lire