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é est disponible pour tous les comptes—aucune approbation requise. 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 un moyen de paiement et éventuellement collecter un prélèvement initial.
  2. Plus tard, vous créez des prélèvements contre cet abonnement avec des montants personnalisés en utilisant le point de terminaison dédié aux prélèvements.
  3. Vous écoutez les webhooks (par ex. payment.succeeded, payment.failed) pour mettre à jour votre système.

Créer un abonnement à la demande

Point de terminaison : POST /checkouts Champs de requête clés (corps) :
Veuillez les trouver dans Créer une session de paiement

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.checkoutSessions.create({
    product_cart: [{ product_id: 'pdt_123', quantity: 1 }],
    billing_address:  { city: 'SF', country: 'US', state: 'CA', street: '1 Market St', zipcode: '94105' },
    customer: { customer_id: 'cus_123' },
    return_url: 'https://example.com/billing/success',
    subscription_data: {
        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,
        }
    }
  });

  console.log(subscription.checkout_url);
}

main().catch(console.error);
Success
{
  "session_id": "cks_123",
  "checkout_url": "https://test.checkout.dodopayments.com/session/cks123"
}

Facturer un abonnement à la demande

Après que le mandat a été autorisé, créez des charges selon vos besoins. Point de terminaison : POST /subscriptions/{subscription_id}/charge Champs de requête clés (corps) :
product_price
integer
requis
Montant à prélever (dans la plus petite unité monétaire). Exemple : pour prélever 25,00 $, passez 2500.
product_currency
string
Remplacement facultatif de la devise pour le prélèvement.
product_description
string
Remplacement facultatif de la description pour ce prélèvement.
adaptive_currency_fees_inclusive
boolean
Si vrai, inclut les frais de devise adaptatifs dans product_price. Si faux, les frais sont ajoutés par-dessus.
metadata
object
Métadonnées supplémentaires pour le paiement. Si omises, 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 });

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" }
La facturation d’un abonnement non à la demande peut échouer. Assurez-vous que l’abonnement comporte 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ûre.
Les schémas de relance en rafale peuvent être signalés comme frauduleux ou suspicion de tests de cartes par nos systèmes de risque et nos processeurs. Évitez les relances groupées ; suivez l’échéancier de relance et les conseils d’alignement temporel ci-dessous.

Principes pour des politiques de réessai sûres

  • Mécanisme de temporisation : utilisez une temporisation exponentielle entre les relances.
  • Limites de relance : plafonnez le nombre total de relances (3 à 4 tentatives maximum).
  • Filtrage intelligent : relancez uniquement en cas d’échecs relançables (ex. : erreurs réseau/émétteur, fonds insuffisants) ; ne relancez jamais après un refus catégorique.
  • Prévention des tests de cartes : ne relancez pas les échecs comme DO_NOT_HONOR, STOLEN_CARD, LOST_CARD, PICKUP_CARD, FRAUDULENT, AUTHENTICATION_FAILURE.
  • Varier les métadonnées (facultatif) : si vous gérez votre propre système de relance, différenciez les relances via les métadonnées (ex. : 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 l’heure d’autorisation

  • Ancrez les relances sur l’horodatage d’autorisation initial pour éviter un comportement de « rafale » sur votre portefeuille.
  • Exemple : si le client commence un essai ou un mandat à 13h10 aujourd’hui, programmez les relances suivantes à 13h10 les jours suivants selon votre temporisation (ex. : +3 jours → 13h10, +7 jours → 13h10).
  • Alternativement, si vous stockez l’heure du dernier paiement réussi T, programmez la tentative suivante à T + X days pour préserver l’alignement sur l’heure de la journée.
Fuseau horaire et heure d’été : 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 devriez 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 savoir si elles peuvent être corrigées par l’utilisateur, consultez la documentation Transaction Failures.
Relancez uniquement pour des problèmes temporaires/douces (par ex. insufficient_funds, issuer_unavailable, processing_error, délais réseau). Si le même refus se répète, interrompez les relances supplémentaires.

Directives de mise en œuvre (sans code)

  • Utilisez un planificateur/une file d’attente qui conserve des horodatages précis ; calculez la prochaine tentative à l’heure exacte du jour (ex. : T + 3 days à la même HH:MM).
  • Conservez et consultez l’heure du dernier paiement réussi T pour calculer la tentative suivante ; ne regroupez pas plusieurs abonnements au même instant.
  • Évaluez toujours la raison du dernier refus ; arrêtez les relances pour les refus catégoriques figurant dans la liste ci-dessus.
  • Limitez les relances simultanées par client et par compte pour éviter les pics accidentels.
  • Communiquez de manière proactive : envoyez un e-mail/SMS au client pour mettre à jour son moyen de paiement avant la prochaine tentative programmée.
  • Utilisez les métadonnées uniquement pour l’observabilité (ex. : retry_attempt) ; n’essayez jamais de « contourner » les systèmes de fraude/risque en faisant tourner des champs sans importance.

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 rapprocher les prélèvements basés sur l’utilisation.

Tests et prochaines étapes

1

Create in test mode

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

Trigger a charge

Appelez le point de terminaison de prélèvement avec un petit product_price (par ex. 100) et vérifiez que vous recevez payment.succeeded.
3

Go live

Passez à votre clé API live une fois que vous avez validé les événements et les mises à jour de l’état interne.

Dépannage

  • 422 Requête invalide : assurez-vous que on_demand.mandate_only est fourni lors de la création et que product_price est fourni pour les prélèvements.
  • 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 la configuration de votre URL de webhook et de votre secret de signature.