Skip to main content

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
For a general subscription setup, see the Subscription Integration Guide.

Prerequisites

  • Dodo Payments merchant account and API key
  • Webhook secret configured and an endpoint to receive events
  • A subscription product in your catalog
Ce guide crée l’abonnement à la demande via une session de paiement (POST /checkouts), qui retourne toujours un hébergé checkout_url. Redirigez le client là-bas pour approuver le mandat, et définissez return_url pour indiquer où il devrait atterrir ensuite.

How on-demand works

  1. You create a subscription with the on_demand object to authorize a payment method and optionally collect an initial charge.
  2. Later, you create charges against that subscription with custom amounts using the dedicated charge endpoint.
  3. 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

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):
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.
Success
La facturation d’un abonnement qui n’est pas à la demande peut échouer. Assurez-vous que l’abonnement contient on_demand: true dans ses détails avant de le facturer.

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

Dodo Payments n’effectue pas de nouvelle tentative automatique des facturations à la demande échouées. Vous êtes responsable de la politique de nouvelle tentative. Suivez les recommandations de nouvelle tentative sécurisée ci-dessous afin d’éviter que nos systèmes de détection de la fraude ne vous signalent pour test de cartes.
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.
Les schémas de nouvelles tentatives en rafale peuvent être signalés comme frauduleux ou comme des tests de cartes présumés par nos systèmes de gestion des risques et nos processeurs. Évitez les nouvelles tentatives regroupées ; suivez le calendrier de backoff et les recommandations d’alignement temporel ci-dessous.

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)
Dernière étape : si le paiement n’a toujours pas été effectué, marquez l’abonnement comme impayé ou annulez-le, selon votre politique. Informez le client pendant ce délai afin qu’il mette à jour son moyen de paiement.

É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 days afin 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_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_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.
Effectuez une nouvelle tentative uniquement en cas de problèmes temporaires ou susceptibles d’être résolus (par exemple, insufficient_funds, issuer_unavailable, processing_error, délais d’attente réseau). Si le même refus se répète, interrompez les nouvelles tentatives.

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 T pour 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 active et demeure facturable via POST /subscriptions/{id}/charge jusqu’à la date d’annulation planifiée.
  • cancel_at_next_billing_date est défini sur true dans l’abonnement.
  • Un webhook subscription.cancelled est é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}
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

Pour distinguer les annulations d’abonnements à la demande de celles des abonnements planifiés dans votre gestionnaire, vérifiez l’indicateur on_demand de l’abonnement lors du traitement du webhook.

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
Pour les flux à la demande, concentrez-vous sur payment.succeeded et payment.failed afin de rapprocher les facturations basées sur l’utilisation. Lorsque payment.failed est suivi de subscription.on_hold, consultez Gestion des frais échoués pour récupérer l’abonnement.

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_only est fourni lors de la création et que product_price est 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.
Dernière modification le 6 août 2026