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
obligatorisk
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
Ange hur kundens wallet-saldo ska användas för att reglera denna debitering.
object
Ytterligare metadata för betalningen. Om den utelämnas används prenumerationens metadata.
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
Hantera misslyckade debiteringar
När en debitering av en on-demand-prenumeration misslyckas avgör du vad som händer härnäst. Till skillnad från schemalagda prenumerationer – där en misslyckad förnyelse stoppar all fortsatt automatisk fakturering – kan on-demand-prenumerationer fortfarande debiteras efter ett misslyckande. Du kan anropa debiteringsendpointen igen som en del av din egen retry-logik.Vad händer vid ett misslyckande
1
Charge attempt fails
Begäran
POST /subscriptions/{subscription_id}/charge returnerar antingen ett felsvar eller slutförs asynkront och skickar en payment.failed-webhook med orsaken till avslaget.2
Subscription may transition to on_hold
Prenumerationen kan övergå till tillståndet
on_hold och skicka en subscription.on_hold-webhook (se Prenumerationstillstånd → On Hold). Detta är en signal – inte ett lås. För on-demand-prenumerationer hindrar on_hold inte att du debiterar igen.3
Retry the charge (your call)
För on-demand-flöden gör Dodo ingen automatisk retry. Du kan anropa
POST /subscriptions/{subscription_id}/charge igen när som helst för att försöka på nytt. Tillämpa den säkra retry-policyn nedan – använd exponentiell backoff, hoppa över hårda avslag och undvik burst-mönster – så att retry-försöken inte flaggas av våra bedrägeri- och risksystem.4
Optionally, ask the customer for a new payment method
Om retry-försöken fortsätter att misslyckas eftersom själva betalningsmetoden är ogiltig (utgånget kort, stängt konto osv.), använd
POST /subscriptions/{subscription_id}/update-payment-method för att samla in en ny från kunden. När det lyckas återgår prenumerationen till active och payment.succeeded följt av subscription.active-webhooks skickas.On-demand jämfört med schemalagda: För schemalagda prenumerationer hanterar Dodo egna retry-försök och kravhantering. För on-demand-prenumerationer ansvarar du för retry-policyn, eftersom bara du vet när nästa debitering ska ske (den styrs av dina användningshändelser, inte av en kalender).
Webhook-sekvens vid en misslyckad on-demand-debitering
Händelserna 3 och 4 utlöses endast efter att en efterföljande debitering har lyckats.
Ansvar för retry
Subscription Dunning – den inbyggda e-postbaserade återhämtningssekvensen – gäller misslyckade förnyelsebetalningar för schemalagda prenumerationer och uppsägningar som initierats av kunden. Den är inte utformad för misslyckade on-demand-debiteringar. Kommunicera direkt med kunden (t.ex. via transaktionell e-post eller en uppmaning i appen) när du avgör att betalningsmetoden behöver uppdateras.Retry-försök för betalningar
Vårt system för bedrägeridetektering kan blockera aggressiva retry-mönster (och flagga dem som möjlig korttestning). Följ en säker retry-policy.Principer för säkra retry-policyer
- Backoff-mekanism: Använd exponentiell backoff mellan retry-försök.
- Retry-gränser: Begränsa det totala antalet retry-försök (högst 3–4 försök).
- Intelligent filtrering: Försök endast igen vid fel som kan göras om (t.ex. nätverks-/issuer-fel, otillräckliga medel); försök aldrig igen vid hårda avslag.
- Förhindra korttestning: Försök inte igen vid fel som
DO_NOT_HONOR,STOLEN_CARD,LOST_CARD,PICKUP_CARD,FRAUDULENT,AUTHENTICATION_FAILURE. - Variera metadata (valfritt): Om du underhåller ett eget retry-system kan du särskilja retry-försök via metadata (t.ex.
retry_attempt).
Föreslaget retry-schema (prenumerationer)
- 1:a försöket: Omedelbart när du skapar debiteringen
- 2:a försöket: Efter 3 dagar
- 3:e försöket: Efter ytterligare 7 dagar (10 dagar totalt)
- 4:e försöket (sista): Efter ytterligare 7 dagar (17 dagar totalt)
Undvik burst-retry; anpassa till auktoriseringstiden
- Förankra retry-försöken i den ursprungliga auktoriseringstidpunkten för att undvika “burst”-beteende i din portfölj.
- Exempel: Om kunden startar en provperiod eller ett mandat kl. 13:10 i dag, schemalägg efterföljande retry-försök kl. 13:10 under följande dagar enligt din backoff (t.ex. +3 dagar → 13:10, +7 dagar → 13:10).
- Om du i stället sparar tiden för den senaste lyckade betalningen
T, schemalägg nästa försök tillT + X daysför att bevara anpassningen till tid på dagen.
Tidszon och DST: använd en konsekvent tidsstandard för schemaläggning och konvertera endast för visning för att bibehålla intervallen.
Avslagskoder som du inte bör försöka igen med
STOLEN_CARDDO_NOT_HONORFRAUDULENTPICKUP_CARDAUTHENTICATION_FAILURELOST_CARD
För en fullständig lista över avslagsorsaker och om de kan korrigeras av användaren, se dokumentationen om
Transaktionsfel.
Implementeringsriktlinjer (ingen kod)
- Använd en schemaläggare/kö som sparar exakta tidsstämplar; beräkna nästa försök vid exakt samma förskjutning i tid på dagen (t.ex.
T + 3 daysvid samma HH:MM). - Underhåll och använd tidsstämpeln för den senaste lyckade betalningen
Tför att beräkna nästa försök; samla inte flera prenumerationer till samma tidpunkt. - Utvärdera alltid den senaste avslagsorsaken; stoppa retry-försök vid hårda avslag i listan ovan.
- Begränsa samtidiga retry-försök per kund och konto för att förhindra oavsiktliga toppar.
- Kommunicera proaktivt: skicka e-post/SMS till kunden för att uppdatera betalningsmetoden före nästa schemalagda försök.
- Använd endast metadata för observerbarhet (t.ex.
retry_attempt); försök aldrig att “undvika” bedrägeri-/risksystem genom att rotera obetydliga fält.
Avslut
On-demand-prenumerationer följer ett annat avslutningsflöde än schemalagda prenumerationer, eftersom det inte finns någon fast faktureringscykel att förankra ett omedelbart slutdatum i.Beteende i kundportalen
När en kund avslutar en on-demand-prenumeration från Customer Portal schemaläggs avslutet som standard till nästa faktureringsdatum. Alternativet Avsluta nu visas avsiktligt inte för on-demand-prenumerationer. Anledningen är att on-demand-prenumerationer inte har förutsägbara återkommande förnyelsedatum – tiden för nästa debitering styrs helt av dina användningshändelser. Genom att schemalägga avslutet till nästa faktureringsdatum förblir mandatet aktivt fram till periodens slut, så att användning som redan pågår fortfarande kan debiteras, varefter prenumerationen avslutas korrekt. Efter att kunden har bekräftat avslutet:- Prenumerationen förblir
activeoch kan fortfarande debiteras viaPOST /subscriptions/{id}/chargefram till det schemalagda avslutsdatumet. cancel_at_next_billing_datesätts tilltrueför prenumerationen.- En
subscription.cancelled-webhook skickas när avslutet träder i kraft.
Om du behöver avsluta prenumerationen omedelbart (till exempel som svar på en återbetalning eller en supportbegäran), avslutar du den programmatiskt via API i stället för att förlita dig på flödet i kundportalen.
Avsluta programmatiskt
Du kan avsluta en on-demand-prenumeration via API när som helst. Du styr om avslutet ska ske omedelbart eller enligt ett schema. Endpoint: PATCH /subscriptions/{subscription_id}- Cancel immediately
- Cancel at next billing date
Ange prenumerationens
status till cancelled för att avsluta den omedelbart. Mandatet återkallas och inga ytterligare debiteringar kan skapas.cURL
Webhooks vid avslut
Spåra resultat med webhooks
Implementera webhook-hantering för att spåra kundresan. Se Implementera Webhooks.- subscription.active: Mandatet auktoriserades och prenumerationen aktiverades
- subscription.failed: Skapandet misslyckades (t.ex. mandatfel)
- subscription.on_hold: Prenumerationen sattes på hold (t.ex. obetalt tillstånd)
- subscription.cancelled: Prenumerationen avslutades helt (se Avslut)
- payment.succeeded: Debiteringen lyckades
- payment.failed: Debiteringen misslyckades
Testning och nästa steg
1
Create in test mode
Använd din test-API-nyckel för att skapa prenumerationen, öppna sedan den returnerade
checkout_url och slutför mandatet.2
Trigger a charge
Anropa debiteringsendpointen med ett litet
product_price (t.ex. 100) och kontrollera att du tar emot payment.succeeded.3
Go live
Byt till din live-API-nyckel när du har validerat händelser och uppdateringar av internt tillstånd.
Felsökning
- 422 Invalid Request: Kontrollera att
on_demand.mandate_onlyanges när prenumerationen skapas och attproduct_priceanges för debiteringar. - Valutafel: Om du åsidosätter
product_currencyska du bekräfta att den stöds för ditt konto och din kund. - Inga webhooks tas emot: Kontrollera konfigurationen av webhook-URL:en och signaturhemligheten.