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.

Fonctionnement des abonnements à la demande

  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.

Créer un abonnement à la demande

Endpoint: POST /checkouts Key request fields (body):
Please find them in Create Checkout Session

Créer un abonnement à la demande

Success

Débiter un abonnement à la demande

After the mandate is authorized, create charges as needed. Endpoint: POST /subscriptions/{subscription_id}/charge Key request fields (body):
integer
requis
Montant à débiter (dans la plus petite unité monétaire). Exemple : pour débiter $25.00, transmettez 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
Le débit d’un abonnement qui n’est pas à la demande échoue avec 400 (SUBSCRIPTION_NOT_ON_DEMAND). Vérifiez que l’abonnement dispose de on_demand: true avant de le débiter. Les abonnements à la demande ne peuvent pas non plus changer de plan : POST /subscriptions/{subscription_id}/change-plan renvoie 422 pour ces abonnements.

Gestion des débits é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 — pas d’un verrouillage. Pour les abonnements à la demande, on_hold ne vous empêche pas d’effectuer un nouveau débit. Un nouveau débit est rejeté avec 409 tant que le paiement précédent est toujours en attente, et avec 429 lorsque plus de quatre paiements ont échoué depuis le dernier paiement réussi.
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’un débit à la demande échoué

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 pour des politiques de nouvelle tentative sûres

  • 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 de nouvelles tentatives recommandé (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.

Évitez les nouvelles tentatives groupées ; alignez-les sur la durée 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.

Consignes 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

La définition ou la suppression de cancel_at_next_billing_date n’envoie aucun webhook dédié. Pour suivre une annulation planifiée, lisez cancel_at_next_billing_date dans la réponse de l’API ou dans la charge utile subscription.updated suivante.
Pour distinguer les annulations à la demande des annulations d’abonnements planifiées dans votre gestionnaire, vérifiez l’indicateur on_demand de l’abonnement lors du traitement du webhook.

Suivre les résultats avec des webhooks

Mettez en œuvre la gestion des webhooks pour suivre le parcours du client. Voir 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é)
  • subscription.cancelled : Abonnement entièrement annulé (voir Annulation)
  • payment.succeeded : Débit réussi
  • payment.failed : Échec du débit
Pour les flux à la demande, concentrez-vous sur payment.succeeded et payment.failed afin de rapprocher les débits basés sur l’usage. Lorsque payment.failed est suivi de subscription.on_hold, consultez la section Gestion des débits échoués pour rétablir l’abonnement.

Tests et prochaines étapes

1

Create in test mode

Utilisez votre clé API de test pour créer l’abonnement, puis ouvrez le checkout_url renvoyé et complétez le mandat.
2

Trigger a charge

Appelez l’endpoint de débit avec un petit product_price (par exemple, 100) et vérifiez que vous recevez payment.succeeded.
3

Go live

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

Résolution des problèmes

  • 422 Invalid Request : Vérifiez que on_demand.mandate_only est fourni lors de la création et que product_price est fourni pour les débits.
  • 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 l’URL de webhook et du secret de signature.
Dernière modification le 26 septembre 2026