Overview
On-demand subscriptions let you authorize a customer’s payment method once and then charge variable amounts whenever you need, instead of on a fixed schedule. This feature is available for all accounts—no approval required. Use this guide to:- Create an on-demand subscription (authorize a mandate with optional initial price)
- Trigger subsequent charges with custom amounts
- Track outcomes using webhooks
Prerequisites
- Dodo Payments merchant account and API key
- Webhook secret configured and an endpoint to receive events
- A subscription product in your catalog
How on-demand works
- You create a subscription with the
on_demandobject to authorize a payment method and optionally collect an initial charge. - Later, you create charges against that subscription with custom amounts using the dedicated charge endpoint.
- You listen to webhooks (e.g.,
payment.succeeded,payment.failed) to update your system.
Create an on-demand subscription
Endpoint: POST /checkouts Key request fields (body):Please find them in Create Checkout Session
Create an on-demand subscription
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
Charge an on-demand subscription
After the mandate is authorized, create charges as needed. Endpoint: POST /subscriptions/{subscription_id}/charge Key request fields (body):Charge request body parameters
Charge request body parameters
integer
requis
Amount to charge (in the smallest currency unit). Example: to charge $25.00, pass
2500.string
Optional currency override for the charge.
string
Optional description override for this charge.
boolean
If true, includes adaptive currency fees within
product_price. If false, fees are added on top.object
Spécifiez comment le solde du portefeuille du client est utilisé pour régler ces frais.
object
Métadonnées supplémentaires pour le paiement. Si elles sont omises, les métadonnées de l’abonnement sont utilisées.
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
Gestion des frais échoués
Lorsqu’une facturation d’un abonnement à la demande échoue, vous décidez de la suite. Contrairement aux abonnements planifiés — pour lesquels un renouvellement échoué arrête toute facturation automatique ultérieure — les abonnements à la demande restent facturables après un échec. Vous pouvez rappeler l’endpoint de facturation dans le cadre de votre propre logique de nouvelle tentative.Que se passe-t-il en cas d’échec ?
1
Charge attempt fails
La requête
POST /subscriptions/{subscription_id}/charge renvoie soit une réponse d’erreur, soit se termine de manière asynchrone et émet un webhook payment.failed contenant le motif du refus.2
Subscription may transition to on_hold
L’abonnement peut passer à l’état
on_hold et émettre un webhook subscription.on_hold (voir États de l’abonnement → En attente). Il s’agit d’un signal — et non d’un verrou. Pour les abonnements à la demande, on_hold ne vous empêche pas de facturer à nouveau.3
Retry the charge (your call)
Pour les flux à la demande, Dodo n’effectue pas de nouvelle tentative automatique. Vous pouvez rappeler
POST /subscriptions/{subscription_id}/charge à tout moment pour effectuer une nouvelle tentative. Appliquez la politique de nouvelle tentative sécurisée ci-dessous — utilisez un backoff exponentiel, ignorez les refus définitifs et évitez les schémas en rafale — afin que les nouvelles tentatives ne soient pas signalées par nos systèmes de lutte contre la fraude et de gestion des risques.4
Optionally, ask the customer for a new payment method
Si les nouvelles tentatives échouent continuellement parce que le moyen de paiement lui-même est défectueux (carte expirée, compte clôturé, etc.), utilisez
POST /subscriptions/{subscription_id}/update-payment-method pour en collecter un nouveau auprès du client. En cas de succès, l’abonnement revient à active et des webhooks payment.succeeded, puis subscription.active sont émis.À la demande ou planifié : pour les abonnements planifiés, Dodo gère ses propres nouvelles tentatives de renouvellement et relances. Pour les abonnements à la demande, vous êtes responsable de la politique de nouvelle tentative, car vous seul savez quand la prochaine facturation doit avoir lieu (elle dépend de vos événements d’utilisation et non d’un calendrier).
Séquence des webhooks lors d’une facturation à la demande échouée
Les événements 3 et 4 ne sont déclenchés qu’après la réussite d’une facturation ultérieure.
Responsabilité des nouvelles tentatives
Relances d’abonnement — la séquence intégrée de récupération par e-mail — est limitée aux paiements de renouvellement échoués des abonnements planifiés et aux annulations initiées par le client. Elle n’est pas conçue pour les échecs de facturation à la demande. Communiquez directement avec le client (par exemple, par e-mail transactionnel ou via une invite dans l’application) lorsque vous déterminez que le moyen de paiement doit être mis à jour.Nouvelles tentatives de paiement
Notre système de détection de la fraude peut bloquer les schémas de nouvelles tentatives agressifs (et les signaler comme des tests de cartes potentiels). Suivez une politique de nouvelle tentative sécurisée.Principes des politiques de nouvelle tentative sécurisées
- Mécanisme de backoff : utilisez un backoff exponentiel entre les nouvelles tentatives.
- Limites de nouvelles tentatives : plafonnez le nombre total de nouvelles tentatives (3 à 4 tentatives maximum).
- Filtrage intelligent : effectuez une nouvelle tentative uniquement en cas d’échecs pouvant faire l’objet d’une nouvelle tentative (par exemple, erreurs réseau ou de l’émetteur, fonds insuffisants) ; n’effectuez jamais de nouvelle tentative en cas de refus définitifs.
- Prévention des tests de cartes : n’effectuez pas de nouvelle tentative pour les échecs tels que
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 nouvelles tentatives, différenciez-les via les métadonnées (par exemple,
retry_attempt).
Calendrier suggéré des nouvelles tentatives (abonnements)
- 1re tentative : immédiatement lors de la création de la facturation
- 2e tentative : après 3 jours
- 3e tentative : 7 jours supplémentaires plus tard (10 jours au total)
- 4e tentative (finale) : 7 jours supplémentaires plus tard (17 jours au total)
Éviter les nouvelles tentatives en rafale ; les aligner sur l’heure d’autorisation
- Ancrez les nouvelles tentatives sur l’horodatage d’autorisation initial afin d’éviter un comportement « en rafale » dans l’ensemble de votre portefeuille.
- Exemple : si le client commence un essai ou un mandat aujourd’hui à 13 h 10, planifiez les nouvelles tentatives de suivi à 13 h 10 les jours suivants, conformément à votre backoff (par exemple, +3 jours → 13 h 10, +7 jours → 13 h 10).
- Si vous enregistrez plutôt l’heure du dernier paiement réussi
T, planifiez la prochaine tentative àT + X daysafin de préserver l’alignement sur l’heure de la journée.
Fuseau horaire et heure d’été : utilisez une référence temporelle cohérente pour la planification et effectuez des conversions uniquement pour l’affichage afin de préserver les intervalles.
Codes de refus pour lesquels vous ne devez pas effectuer de nouvelle tentative
STOLEN_CARDDO_NOT_HONORFRAUDULENTPICKUP_CARDAUTHENTICATION_FAILURELOST_CARD
Pour obtenir la liste complète des motifs de refus et savoir s’ils peuvent être corrigés par l’utilisateur, consultez la documentation
Échecs de transaction.
Recommandations d’implémentation (sans code)
- Utilisez un planificateur ou une file d’attente qui conserve des horodatages précis ; calculez la prochaine tentative à l’offset exact de l’heure de la journée (par exemple,
T + 3 daysà la même heure HH:MM). - Conservez et utilisez l’horodatage du dernier paiement réussi
Tpour calculer la prochaine tentative ; ne regroupez pas plusieurs abonnements au même instant. - Évaluez toujours le motif du dernier refus ; arrêtez les nouvelles tentatives pour les refus définitifs de la liste d’exclusion ci-dessus.
- Limitez le nombre de nouvelles tentatives simultanées par client et par compte afin d’éviter les pics accidentels.
- Communiquez de manière proactive : envoyez un e-mail ou un SMS au client pour qu’il mette à jour son moyen de paiement avant la prochaine tentative planifiée.
- Utilisez les métadonnées uniquement à des fins d’observabilité (par exemple,
retry_attempt) ; n’essayez jamais de « contourner » les systèmes de fraude ou de gestion des risques en faisant varier des champs sans importance.
Annulation
Les abonnements à la demande suivent un processus d’annulation différent de celui des abonnements planifiés, car il n’existe aucun cycle de facturation fixe permettant d’ancrer une date de fin immédiate.Comportement du Customer Portal
Lorsqu’un client annule un abonnement à la demande depuis le Customer Portal, l’annulation est planifiée pour la prochaine date de facturation par défaut. L’option Annuler maintenant n’est volontairement pas affichée pour les abonnements à la demande. La raison est la suivante : les abonnements à la demande n’ont pas de dates de renouvellement récurrentes prévisibles — l’heure de la prochaine facturation dépend entièrement de vos événements d’utilisation. Planifier l’annulation à la prochaine date de facturation maintient le mandat actif jusqu’à la fin de la période afin que toute utilisation en cours puisse encore être facturée, puis met fin proprement à l’abonnement. Après confirmation de l’annulation par le client :- L’abonnement reste
activeet demeure facturable viaPOST /subscriptions/{id}/chargejusqu’à la date d’annulation planifiée. cancel_at_next_billing_dateest défini surtruedans l’abonnement.- Un webhook
subscription.cancelledest émis lorsque l’annulation prend effet.
Si vous devez mettre fin immédiatement à l’abonnement (par exemple, en réponse à un remboursement ou à une demande d’assistance), annulez-le par programmation via l’API plutôt que de vous appuyer sur le flux du Customer Portal.
Annuler par programmation
Vous pouvez annuler un abonnement à la demande via l’API à tout moment. Vous contrôlez si l’annulation est immédiate ou planifiée. Endpoint : PATCH /subscriptions/{subscription_id}- Cancel immediately
- Cancel at next billing date
Définissez
status de l’abonnement sur cancelled pour y mettre fin immédiatement. Le mandat est révoqué et aucune nouvelle facturation ne peut être créée.cURL
Webhooks lors de l’annulation
Suivre les résultats avec les webhooks
Implémentez la gestion des webhooks pour suivre le parcours du client. Consultez Implémentation des webhooks.- subscription.active : mandat autorisé et abonnement activé
- subscription.failed : création échouée (par exemple, échec du mandat)
- subscription.on_hold : abonnement mis en attente (par exemple, état impayé)
- subscription.cancelled : abonnement entièrement annulé (voir Annulation)
- payment.succeeded : facturation réussie
- payment.failed : facturation échouée
Tests et prochaines étapes
1
Create in test mode
Utilisez votre clé API de test pour créer l’abonnement, puis ouvrez
checkout_url renvoyé et terminez le mandat.2
Trigger a charge
Appelez l’endpoint de facturation avec un petit
product_price (par exemple, 100) et vérifiez que vous recevez payment.succeeded.3
Go live
Passez à votre clé API de production après avoir validé les événements et les mises à jour de l’état interne.
Résolution des problèmes
- 422 Invalid Request : assurez-vous que
on_demand.mandate_onlyest fourni lors de la création et queproduct_priceest fourni pour les facturations. - Erreurs de devise : si vous remplacez
product_currency, vérifiez qu’elle est prise en charge pour votre compte et votre client. - Aucun webhook reçu : vérifiez la configuration de l’URL de votre webhook et de son secret de signature.