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
This guide creates the on-demand subscription through a checkout session (POST /checkouts), which always returns a hosted checkout_url. Redirect the customer there to approve the mandate, and set return_url to where they should land afterward.

So funktioniert On-Demand

  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.

On-Demand-Abonnement erstellen

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

On-Demand-Abonnement erstellen

Success

On-Demand-Abonnement belasten

After the mandate is authorized, create charges as needed. Endpoint: POST /subscriptions/{subscription_id}/charge Key request fields (body):
integer
erforderlich
Belastungsbetrag (in der kleinsten Währungseinheit). Beispiel: Um 25,00$ abzubuchen, übergeben Sie 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.
Success
Das Belasten eines Abonnements, das kein On-Demand-Abonnement ist, schlägt mit 400 (SUBSCRIPTION_NOT_ON_DEMAND) fehl. Stellen Sie sicher, dass das Abonnement über on_demand: true verfügt, bevor Sie es belasten. Bei On-Demand-Abonnements kann außerdem der Plan nicht geändert werden: POST /subscriptions/{subscription_id}/change-plan gibt für diese 422 zurück.

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 geschieht

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 hindert on_hold Sie nicht daran, erneut eine Belastung auszulösen. Eine neue Belastung wird mit 409 abgelehnt, solange die vorherige Zahlung noch aussteht, und mit 429, sobald seit der letzten erfolgreichen Zahlung mehr als vier Zahlungen fehlgeschlagen sind.
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-Abfolge bei einer fehlgeschlagenen On-Demand-Belastung

Die Ereignisse 3 und 4 werden erst ausgelöst, nachdem eine Folgebelastung erfolgreich war.

Verantwortung für Retries

Dodo Payments führt keine automatischen Retries für fehlgeschlagene On-Demand-Belastungen durch. Du bist für die Retry-Richtlinie verantwortlich. Befolge die unten aufgeführten Richtlinien für sichere Retries, damit unsere Systeme zur Betrugserkennung dich nicht als Card Testing einstufen.
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.
Burst-Retry-Muster können von unseren Risikosystemen und Zahlungsabwicklern als betrügerisch oder als vermutetes Card Testing markiert werden. Vermeide gebündelte Retries und befolge den unten beschriebenen Backoff-Zeitplan sowie die Hinweise zur zeitlichen Abstimmung.

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).

Empfohlener 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)
Letzter Schritt: Wenn die Zahlung weiterhin aussteht, markiere das Abonnement abhängig von deiner Richtlinie als unbezahlt oder kündige es. Informiere den Kunden innerhalb dieses Zeitfensters darüber, seine Zahlungsmethode zu aktualisieren.

Burst-Retries vermeiden und an der Autorisierungsdauer 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 T speicherst, plane den nächsten Versuch für T + 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 Sie keinen Retry durchführen sollten

  • STOLEN_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_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.
Wiederhole nur bei vorübergehenden Problemen (z. B. insufficient_funds, issuer_unavailable, processing_error, Netzwerk-Timeouts). Wenn dieselbe Ablehnung erneut auftritt, pausiere weitere Retries.

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 days zur gleichen HH:MM-Zeit).
  • Speichere den Zeitstempel der letzten erfolgreichen Zahlung T und 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 im 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 active und kann bis zum geplanten Kündigungsdatum weiterhin über POST /subscriptions/{id}/charge belastet werden.
  • cancel_at_next_billing_date wird im Abonnement auf true gesetzt.
  • 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}
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 Kündigung

Das Setzen oder Löschen von cancel_at_next_billing_date sendet keinen dedizierten Webhook. Um eine geplante Kündigung zu verfolgen, lesen Sie cancel_at_next_billing_date aus der API-Antwort oder aus dem nächsten subscription.updated-Payload.
Um On-Demand-Kündigungen von Kündigungen geplanter Abonnements in Ihrem Handler zu unterscheiden, prüfen Sie beim Verarbeiten des Webhooks das on_demand-Flag des Abonnements.

Ergebnisse mit Webhooks verfolgen

Implementieren Sie die Webhook-Verarbeitung, um die Customer Journey zu verfolgen. Siehe Webhooks.
  • subscription.active: Mandate autorisiert und Abonnement aktiviert
  • subscription.failed: Erstellung fehlgeschlagen (z. B. aufgrund eines Mandate-Fehlers)
  • subscription.on_hold: Abonnement auf Hold gesetzt (z. B. bei ausstehender Zahlung)
  • subscription.cancelled: Abonnement vollständig gekündigt (siehe Kündigung)
  • payment.succeeded: Belastung erfolgreich
  • payment.failed: Belastung fehlgeschlagen
Konzentrieren Sie sich bei On-Demand-Abläufen auf payment.succeeded und payment.failed, um nutzungsbasierte Belastungen abzugleichen. Wenn auf payment.failed ein subscription.on_hold folgt, lesen Sie Umgang mit fehlgeschlagenen Belastungen, um das Abonnement wiederherzustellen.

Testen und nächste Schritte

1

Create in test mode

Verwenden Sie Ihren Test-API-Key, um das Abonnement zu erstellen. Öffnen Sie anschließend den zurückgegebenen checkout_url und schließen Sie das Mandate ab.
2

Trigger a charge

Rufen Sie den Belastungsendpunkt mit einem kleinen product_price auf (z. B. 100) und überprüfen Sie, ob Sie payment.succeeded erhalten.
3

Go live

Wechseln Sie zu Ihrem Live-API-Key, sobald Sie die Ereignisse und internen Statusaktualisierungen validiert haben.

Fehlerbehebung

  • 422 Invalid Request: Stellen Sie sicher, dass on_demand.mandate_only bei der Erstellung und product_price für Belastungen angegeben wird.
  • Währungsfehler: Wenn Sie product_currency überschreiben, bestätigen Sie, dass die Währung für Ihr Konto und Ihren Kunden unterstützt wird.
  • Keine Webhooks empfangen: Überprüfen Sie die Konfiguration Ihrer Webhook-URL und des Signaturgeheimnisses.
Zuletzt geändert am 26. September 2026