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
Den här guiden skapar prenumerationen på begäran genom en utcheckningssession (POST /checkouts), som alltid returnerar en värdtjänst checkout_url. Omdirigera kunden dit för att godkänna mandatet och ställ in return_url där de ska landa efteråt.

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
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.
Success
Det kan misslyckas att debitera en prenumeration som inte är on-demand. Kontrollera att prenumerationen har on_demand: true i sina detaljer innan du debiterar den.

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

Dodo Payments gör inga automatiska retry-försök för misslyckade on-demand-debiteringar. Du ansvarar för retry-policyn. Följ riktlinjerna för säkra retry-försök nedan för att undvika att våra system för bedrägeridetektering flaggar dem som korttestning.
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.
Burst-mönster vid retry kan flaggas som bedrägliga eller som misstänkt korttestning av våra risksystem och betalningsprocessorer. Undvik klustrade retry-försök; följ schemat för backoff och riktlinjerna för tidsanpassning nedan.

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)
Sista steget: om betalningen fortfarande inte har genomförts, markera prenumerationen som obetald eller avsluta den enligt din policy. Meddela kunden under perioden att betalningsmetoden behöver uppdateras.

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 till T + X days fö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_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_CARD
För en fullständig lista över avslagsorsaker och om de kan korrigeras av användaren, se dokumentationen om Transaktionsfel.
Försök endast igen vid mjuka/tillfälliga problem (t.ex. insufficient_funds, issuer_unavailable, processing_error, nätverkstimeouts). Om samma avslag upprepas ska du pausa ytterligare retry-försök.

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 days vid samma HH:MM).
  • Underhåll och använd tidsstämpeln för den senaste lyckade betalningen T fö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 active och kan fortfarande debiteras via POST /subscriptions/{id}/charge fram till det schemalagda avslutsdatumet.
  • cancel_at_next_billing_date sätts till true fö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}
Ange prenumerationens status till cancelled för att avsluta den omedelbart. Mandatet återkallas och inga ytterligare debiteringar kan skapas.
cURL

Webhooks vid avslut

För att skilja on-demand-avslut från avslut av schemalagda prenumerationer i din handler kontrollerar du prenumerationens on_demand-flagga när du behandlar webhooken.

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
För on-demand-flöden fokuserar du på payment.succeeded och payment.failed för att stämma av användningsbaserade debiteringar. När payment.failed följs av subscription.on_hold, se Hantera misslyckade debiteringar för att återställa prenumerationen.

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_only anges när prenumerationen skapas och att product_price anges för debiteringar.
  • Valutafel: Om du åsidosätter product_currency ska 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.
Senast ändrad 6 augusti 2026