Passer au contenu principal

Vue d’ensemble

Les abonnements à la demande vous permettent d’autoriser une méthode de paiement d’un client une fois, puis de facturer des montants variables chaque fois que vous en avez besoin, au lieu de suivre un calendrier fixe.
Cette fonctionnalité peut devoir être activée sur votre compte. Contactez le support si vous ne la voyez pas dans votre tableau de bord.
Utilisez ce guide pour :
  • Créer un abonnement à la demande (autoriser un mandat avec un prix initial optionnel)
  • Déclencher des charges ultérieures avec des montants personnalisés
  • Suivre les résultats à l’aide de webhooks
Pour une configuration d’abonnement générale, consultez le Guide d’intégration des abonnements.

Prérequis

  • Compte marchand Dodo Payments et clé API
  • Secret de webhook configuré et un point de terminaison pour recevoir des événements
  • Un produit d’abonnement dans votre catalogue
Si vous souhaitez que le client approuve le mandat via un paiement hébergé, définissez payment_link: true et fournissez un return_url.

Comment fonctionne la demande

  1. Vous créez un abonnement avec l’objet on_demand pour autoriser une méthode de paiement et éventuellement collecter une charge initiale.
  2. Plus tard, vous créez des charges contre cet abonnement avec des montants personnalisés en utilisant le point de terminaison de charge dédié.
  3. Vous écoutez les webhooks (par exemple, payment.succeeded, payment.failed) pour mettre à jour votre système.

Créer un abonnement à la demande

Point de terminaison : POST /subscriptions Champs de requête clés (corps) :
product_id
string
required
ID du produit pour l’abonnement.
quantity
integer
required
Nombre d’unités. Minimum 1.
billing
object
required
Adresse de facturation pour le client.
customer
object
required
Soit attacher un client existant, soit fournir les détails du client.
Si vrai, crée un lien de paiement hébergé pour l’autorisation du mandat et le paiement initial optionnel.
return_url
string
Où rediriger le client après avoir complété le paiement hébergé.
on_demand.mandate_only
boolean
required
Si vrai, autorise la méthode de paiement sans facturer le client lors de la création.
on_demand.product_price
integer
Montant de la charge initiale (dans la plus petite unité monétaire). Si spécifié, cette valeur remplace le prix original du produit défini lors de la création du produit. Si omis, le prix stocké du produit est utilisé. Exemple : pour facturer 1,00 $, passez 100.
on_demand.product_currency
string
Remplacement de la devise optionnel pour la charge initiale. Par défaut, c’est la devise du produit.
on_demand.product_description
string
Remplacement de la description optionnel pour la facturation et les lignes d’articles.
on_demand.adaptive_currency_fees_inclusive
boolean
Si vrai, inclut les frais de devise adaptatifs dans product_price. Si faux, les frais sont ajoutés en plus. Ignoré lorsque la tarification adaptative est désactivée.

Créer un abonnement à la demande

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // defaults to 'live_mode'
});

async function main() {
  const subscription = await client.subscriptions.create({
    billing: { city: 'SF', country: 'US', state: 'CA', street: '1 Market St', zipcode: '94105' },
    customer: { customer_id: 'customer_123' },
    product_id: 'prod_sub_123',
    quantity: 1,
    payment_link: true,
    return_url: 'https://example.com/billing/success',
    on_demand: {
      mandate_only: true, // set false to collect an initial charge
      // product_price: 1000, // optional: charge $10.00 now if mandate_only is false
      // product_currency: 'USD',
      // product_description: 'Custom initial charge',
      // adaptive_currency_fees_inclusive: false,
    },
  });

  // If payment_link was true, redirect the customer to authorize the mandate
  console.log(subscription.payment_link);
}

main().catch(console.error);
Définissez payment_link: true, redirigez le client vers payment_link pour compléter l’autorisation du mandat.
Success
{
  "subscription_id": "sub_123",
  "payment_link": "https://pay.dodopayments.com/checkout/...",
  "customer": { "customer_id": "customer_123", "email": "[email protected]", "name": "Alex Doe" },
  "metadata": {},
  "recurring_pre_tax_amount": 0,
  "addons": []
}

Facturer un abonnement à la demande

Après que le mandat a été autorisé, créez des charges selon les besoins. Point de terminaison : POST /subscriptions/{subscription_id}/charge Champs de requête clés (corps) :
product_price
integer
required
Montant à facturer (dans la plus petite unité monétaire). Exemple : pour facturer 25,00 $, passez 2500.
product_currency
string
Remplacement de la devise optionnel pour la charge.
product_description
string
Remplacement de la description optionnel pour cette charge.
adaptive_currency_fees_inclusive
boolean
Si vrai, inclut les frais de devise adaptatifs dans product_price. Si faux, les frais sont ajoutés en plus.
metadata
object
Métadonnées supplémentaires pour le paiement. Si omis, les métadonnées de l’abonnement sont utilisées.
import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // defaults to 'live_mode'
});

async function chargeNow(subscriptionId) {
  const res = await client.subscriptions.charge(subscriptionId, { product_price: 2500 });
  console.log(res.payment_id);
}

chargeNow('sub_123').catch(console.error);
Success
{ "payment_id": "pay_abc123" }
Facturer un abonnement qui n’est pas à la demande peut échouer. Assurez-vous que l’abonnement a on_demand: true dans ses détails avant de facturer.

Réessayer les paiements

Notre système de détection de fraude peut bloquer des modèles de réessai agressifs (et peut les signaler comme des tests de carte potentiels). Suivez une politique de réessai sécurisée.
Les modèles de réessai en rafale peuvent être signalés comme frauduleux ou soupçonnés de tests de carte par nos systèmes de risque et nos processeurs. Évitez les réessais groupés ; suivez le calendrier de retour et les conseils d’alignement temporel ci-dessous.

Principes pour des politiques de réessai sécurisées

  • Mécanisme de retour : Utilisez un retour exponentiel entre les réessais.
  • Limites de réessai : Limitez le nombre total de réessais (3 à 4 tentatives maximum).
  • Filtrage intelligent : Réessayez uniquement en cas d’échecs réessayables (par exemple, erreurs réseau/émetteur, fonds insuffisants) ; ne réessayez jamais les refus fermes.
  • Prévention des tests de carte : Ne réessayez pas les échecs comme DO_NOT_HONOR, STOLEN_CARD, LOST_CARD, PICKUP_CARD, FRAUDULENT, AUTHENTICATION_FAILURE.
  • Varier les métadonnées (optionnel) : Si vous maintenez votre propre système de réessai, différenciez les réessais via des métadonnées (par exemple, retry_attempt).

Calendrier de réessai suggéré (abonnements)

  • 1ère tentative : Immédiate lors de la création de la charge
  • 2ème tentative : Après 3 jours
  • 3ème tentative : Après 7 jours supplémentaires (10 jours au total)
  • 4ème tentative (finale) : Après 7 jours supplémentaires (17 jours au total)
Étape finale : si toujours impayé, marquez l’abonnement comme impayé ou annulez-le, selon votre politique. Informez le client pendant la période pour mettre à jour sa méthode de paiement.

Évitez les réessais en rafale ; alignez-vous sur le temps d’autorisation

  • Ancrez les réessais à l’horodatage d’autorisation original pour éviter un comportement de “rafale” dans votre portefeuille.
  • Exemple : Si le client commence un essai ou un mandat à 13h10 aujourd’hui, planifiez les réessais de suivi à 13h10 les jours suivants selon votre retour (par exemple, +3 jours → 13h10, +7 jours → 13h10).
  • Alternativement, si vous stockez le dernier temps de paiement réussi T, planifiez la prochaine tentative à T + X days pour préserver l’alignement horaire.
Fuseau horaire et DST : utilisez une norme horaire cohérente pour la planification et convertissez uniquement pour l’affichage afin de maintenir les intervalles.

Codes de refus que vous ne devez pas réessayer

  • STOLEN_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_CARD
Pour une liste complète des raisons de refus et si elles peuvent être corrigées par l’utilisateur, consultez la documentation sur les Échecs de transaction.
Ne réessayez que sur des problèmes temporaires/doux (par exemple, insufficient_funds, issuer_unavailable, processing_error, délais d’attente réseau). Si le même refus se répète, mettez en pause les réessais supplémentaires.

Directives de mise en œuvre (sans code)

  • Utilisez un planificateur/une file d’attente qui persiste des horodatages précis ; calculez la prochaine tentative à l’heure exacte (par exemple, T + 3 days à la même HH:MM).
  • Maintenez et référencez le dernier horodatage de paiement réussi T pour calculer la prochaine tentative ; ne regroupez pas plusieurs abonnements au même instant.
  • Évaluez toujours la dernière raison de refus ; arrêtez les réessais pour les refus fermes dans la liste d’ignorés ci-dessus.
  • Limitez les réessais simultanés par client et par compte pour éviter des pics accidentels.
  • Communiquez de manière proactive : envoyez un e-mail/SMS au client pour mettre à jour sa méthode de paiement avant la prochaine tentative prévue.
  • Utilisez les métadonnées uniquement pour l’observabilité (par exemple, retry_attempt) ; n’essayez jamais de “contourner” les systèmes de fraude/de risque en faisant tourner des champs sans conséquence.

Suivre les résultats avec des webhooks

Implémentez la gestion des webhooks pour suivre le parcours du client. Voir Implémentation des Webhooks.
  • subscription.active : Mandat autorisé et abonnement activé
  • subscription.failed : Échec de la création (par exemple, échec du mandat)
  • subscription.on_hold : Abonnement mis en attente (par exemple, état impayé)
  • payment.succeeded : Charge réussie
  • payment.failed : Échec de la charge
Pour les flux à la demande, concentrez-vous sur payment.succeeded et payment.failed pour réconcilier les charges basées sur l’utilisation.

Tests et prochaines étapes

1

Créer en mode test

Utilisez votre clé API de test pour créer l’abonnement avec payment_link: true, puis ouvrez le lien et complétez le mandat.
2

Déclencher une charge

Appelez le point de terminaison de charge avec un petit product_price (par exemple, 100) et vérifiez que vous recevez payment.succeeded.
3

Passer en production

Passez à votre clé API en production une fois que vous avez validé les événements et les mises à jour d’état internes.

Dépannage

  • 422 Requête invalide : Assurez-vous que on_demand.mandate_only est fourni lors de la création et product_price est fourni pour les charges.
  • Erreurs de devise : Si vous remplacez product_currency, confirmez qu’elle est prise en charge pour votre compte et votre client.
  • Aucun webhook reçu : Vérifiez votre URL de webhook et la configuration du secret de signature.