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
erforderlich
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
Legt fest, wie das Wallet-Guthaben des Kunden verwendet wird, um diese Belastung zu begleichen.
object
Zusätzliche Metadaten für die Zahlung. Wenn nicht angegeben, werden die Metadaten des Abonnements verwendet.
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
Umgang mit fehlgeschlagenen Belastungen
Wenn eine Belastung eines On-Demand-Abonnements fehlschlägt, entscheidest du, was als Nächstes passiert. Anders als bei geplanten Abonnements – bei denen eine fehlgeschlagene Verlängerung die weitere automatische Abrechnung beendet – können On-Demand-Abonnements nach einem Fehler weiterhin belastet werden. Du kannst den Charge-Endpoint im Rahmen deiner eigenen Retry-Logik erneut aufrufen.Was bei einem Fehler passiert
1
Charge attempt fails
Die Anfrage
POST /subscriptions/{subscription_id}/charge gibt entweder eine Fehlerantwort zurück oder wird asynchron abgeschlossen und löst einen payment.failed-Webhook mit dem Ablehnungsgrund aus.2
Subscription may transition to on_hold
Das Abonnement kann in den Status
on_hold wechseln und einen subscription.on_hold-Webhook auslösen (siehe Abonnementstatus → On Hold). Dies ist ein Signal – keine Sperre. Bei On-Demand-Abonnements verhindert on_hold nicht, dass du erneut eine Belastung vornimmst.3
Retry the charge (your call)
Bei On-Demand-Abläufen führt Dodo keine automatischen Retries durch. Du kannst
POST /subscriptions/{subscription_id}/charge jederzeit erneut aufrufen. Wende die unten beschriebene Richtlinie für sichere Retries an – verwende exponentielles Backoff, überspringe endgültige Ablehnungen und vermeide Burst-Muster –, damit Retries nicht von unseren Betrugs- und Risikosystemen markiert werden.4
Optionally, ask the customer for a new payment method
Wenn Retries weiterhin fehlschlagen, weil die Zahlungsmethode selbst nicht funktioniert (abgelaufene Karte, geschlossenes Konto usw.), verwende
POST /subscriptions/{subscription_id}/update-payment-method, um eine neue Zahlungsmethode vom Kunden zu erfassen. Bei Erfolg kehrt das Abonnement zu active zurück und anschließend werden payment.succeeded- und subscription.active-Webhooks ausgelöst.On-Demand vs. geplant: Bei geplanten Abonnements führt Dodo eigene Retries für Verlängerungen und Dunning durch. Bei On-Demand-Abonnements legst du die Retry-Richtlinie selbst fest, da nur du weißt, wann die nächste Belastung erfolgen soll (sie wird durch deine Nutzungsereignisse und nicht durch einen Kalender ausgelöst).
Webhook-Sequenz bei einer fehlgeschlagenen On-Demand-Belastung
Die Ereignisse 3 und 4 werden erst ausgelöst, nachdem eine Folgebelastung erfolgreich war.
Verantwortung für Retries
Subscription Dunning – die integrierte E-Mail-Wiederherstellungssequenz – ist auf fehlgeschlagene Verlängerungszahlungen bei geplanten Abonnements und vom Kunden veranlasste Kündigungen beschränkt. Sie ist nicht für fehlgeschlagene On-Demand-Belastungen vorgesehen. Kommuniziere direkt mit dem Kunden (z. B. per Transaktions-E-Mail oder In-App-Aufforderung), wenn du entscheidest, dass die Zahlungsmethode aktualisiert werden muss.Zahlungs-Retries
Unser System zur Betrugserkennung kann aggressive Retry-Muster blockieren (und sie als potenzielles Card Testing markieren). Befolge eine sichere Retry-Richtlinie.Grundsätze für sichere Retry-Richtlinien
- Backoff-Mechanismus: Verwende exponentielles Backoff zwischen Retries.
- Retry-Limits: Begrenze die Gesamtzahl der Retries (maximal 3–4 Versuche).
- Intelligente Filterung: Wiederhole nur bei wiederholbaren Fehlern (z. B. Netzwerk-/Issuer-Fehlern, unzureichendem Guthaben); wiederhole niemals endgültige Ablehnungen.
- Verhinderung von Card Testing: Wiederhole keine Fehler wie
DO_NOT_HONOR,STOLEN_CARD,LOST_CARD,PICKUP_CARD,FRAUDULENT,AUTHENTICATION_FAILURE. - Metadaten variieren (optional): Wenn du ein eigenes Retry-System unterhältst, unterscheide Retries über Metadaten (z. B.
retry_attempt).
Vorgeschlagener Retry-Zeitplan (Abonnements)
- 1. Versuch: Sofort beim Erstellen der Belastung
- 2. Versuch: Nach 3 Tagen
- 3. Versuch: Nach weiteren 7 Tagen (insgesamt 10 Tage)
- 4. Versuch (final): Nach weiteren 7 Tagen (insgesamt 17 Tage)
Burst-Retries vermeiden und an der Autorisierungszeit ausrichten
- Verankere Retries am ursprünglichen Zeitstempel der Autorisierung, um ein „Burst“-Verhalten über dein gesamtes Portfolio hinweg zu vermeiden.
- Beispiel: Wenn der Kunde heute um 13:10 Uhr einen Testzeitraum oder ein Mandat startet, plane Folge-Retries an den darauffolgenden Tagen gemäß deinem Backoff um 13:10 Uhr (z. B. +3 Tage → 13:10 Uhr, +7 Tage → 13:10 Uhr).
- Wenn du alternativ die Zeit der letzten erfolgreichen Zahlung
Tspeicherst, plane den nächsten Versuch fürT + X days, um die zeitliche Ausrichtung beizubehalten.
Zeitzone und DST: Verwende für die Planung einen einheitlichen Zeitstandard und rechne nur für die Anzeige um, damit die Intervalle erhalten bleiben.
Ablehnungscodes, bei denen du keinen Retry durchführen solltest
STOLEN_CARDDO_NOT_HONORFRAUDULENTPICKUP_CARDAUTHENTICATION_FAILURELOST_CARD
Eine umfassende Liste der Ablehnungsgründe und Informationen dazu, ob sie vom Benutzer korrigiert werden können, findest du in der
Dokumentation zu Transaktionsfehlern.
Implementierungsrichtlinien (ohne Code)
- Verwende einen Scheduler/eine Queue, die präzise Zeitstempel speichert; berechne den nächsten Versuch zum exakten Tageszeitpunkt des Offsets (z. B.
T + 3 dayszur gleichen HH:MM-Zeit). - Speichere den Zeitstempel der letzten erfolgreichen Zahlung
Tund verwende ihn zur Berechnung des nächsten Versuchs; bündele nicht mehrere Abonnements zum selben Zeitpunkt. - Werte immer den letzten Ablehnungsgrund aus und stoppe Retries bei endgültigen Ablehnungen aus der obigen Ausschlussliste.
- Begrenze gleichzeitige Retries pro Kunde und Konto, um versehentliche Lastspitzen zu verhindern.
- Kommuniziere proaktiv: Sende dem Kunden eine E-Mail/SMS, damit er seine Zahlungsmethode vor dem nächsten geplanten Versuch aktualisiert.
- Verwende Metadaten ausschließlich zur Beobachtung (z. B.
retry_attempt); versuche niemals, Betrugs-/Risikosysteme durch das Rotieren unwesentlicher Felder zu „umgehen“.
Kündigung
On-Demand-Abonnements folgen einem anderen Kündigungsablauf als geplante Abonnements, da es keinen festen Abrechnungszyklus gibt, an dem ein sofortiges Enddatum ausgerichtet werden kann.Verhalten des Customer Portal
Wenn ein Kunde ein On-Demand-Abonnement über das Customer Portal kündigt, wird die Kündigung standardmäßig für das nächste Abrechnungsdatum geplant. Die Option Jetzt kündigen wird bei On-Demand-Abonnements absichtlich nicht angezeigt. Der Grund: On-Demand-Abonnements haben keine vorhersehbaren wiederkehrenden Verlängerungsdaten – der Zeitpunkt der nächsten Belastung wird vollständig durch deine Nutzungsereignisse bestimmt. Durch die Planung der Kündigung zum nächsten Abrechnungsdatum bleibt das Mandat bis zum Ende des Zeitraums aktiv, sodass laufende Nutzung weiterhin belastet werden kann. Anschließend wird das Abonnement ordnungsgemäß beendet. Nachdem der Kunde die Kündigung bestätigt hat:- Das Abonnement bleibt
activeund kann bis zum geplanten Kündigungsdatum weiterhin überPOST /subscriptions/{id}/chargebelastet werden. cancel_at_next_billing_datewird im Abonnement auftruegesetzt.- Wenn die Kündigung wirksam wird, wird ein
subscription.cancelled-Webhook ausgelöst.
Wenn du das Abonnement sofort beenden musst (zum Beispiel als Reaktion auf eine Rückerstattung oder eine Supportanfrage), kündige es programmgesteuert über die API, anstatt dich auf den Ablauf im Customer Portal zu verlassen.
Programmgesteuert kündigen
Du kannst ein On-Demand-Abonnement jederzeit über die API kündigen. Du entscheidest, ob die Kündigung sofort oder geplant erfolgen soll. Endpoint: PATCH /subscriptions/{subscription_id}- Cancel immediately
- Cancel at next billing date
Setze
status des Abonnements auf cancelled, um es sofort zu beenden. Das Mandat wird widerrufen und es können keine weiteren Belastungen erstellt werden.cURL
Webhooks bei der Kündigung
Ergebnisse mit Webhooks verfolgen
Implementiere die Verarbeitung von Webhooks, um die Customer Journey zu verfolgen. Siehe Webhooks implementieren.- subscription.active: Mandat autorisiert und Abonnement aktiviert
- subscription.failed: Erstellung fehlgeschlagen (z. B. Mandatsfehler)
- subscription.on_hold: Abonnement pausiert (z. B. Status „unbezahlt“)
- subscription.cancelled: Abonnement vollständig gekündigt (siehe Kündigung)
- payment.succeeded: Belastung erfolgreich
- payment.failed: Belastung fehlgeschlagen
Testen und nächste Schritte
1
Create in test mode
Verwende deinen Test-API-Key, um das Abonnement zu erstellen. Öffne anschließend den zurückgegebenen
checkout_url und schließe das Mandat ab.2
Trigger a charge
Rufe den Charge-Endpoint mit einem kleinen
product_price (z. B. 100) auf und überprüfe, dass du payment.succeeded erhältst.3
Go live
Wechsle zu deinem Live-API-Key, sobald du die Ereignisse und internen Statusaktualisierungen validiert hast.
Fehlerbehebung
- 422 Invalid Request: Stelle sicher, dass
on_demand.mandate_onlybei der Erstellung undproduct_pricefür Belastungen angegeben wird. - Währungsfehler: Wenn du
product_currencyüberschreibst, bestätige, dass die Währung für dein Konto und deinen Kunden unterstützt wird. - Keine Webhooks empfangen: Überprüfe die Konfiguration deiner Webhook-URL und des Signaturgeheimnisses.