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.

Så fungerar 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.

Skapa en On-Demand-prenumeration

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

Skapa en On-Demand-prenumeration

Success

Debitera en On-Demand-prenumeration

After the mandate is authorized, create charges as needed. Endpoint: POST /subscriptions/{subscription_id}/charge Key request fields (body):
integer
obligatorisk
Debiteringsbelopp (i den minsta valutaenheten). Exempel: för att debitera $25.00 skickar du 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 går inte att debitera en prenumeration som inte är On-Demand och anropet misslyckas med 400 (SUBSCRIPTION_NOT_ON_DEMAND). Kontrollera att prenumerationen har on_demand: true innan du debiterar den. On-Demand-prenumerationer kan inte heller byta plan: POST /subscriptions/{subscription_id}/change-plan returnerar 422 för dem.

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 dig från att försöka debitera igen. En ny debitering avvisas med 409 medan den föregående betalningen fortfarande behandlas, och med 429 när fler än fyra betalningar har misslyckats sedan den senaste lyckade betalningen.
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.

Payment retries

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-retries; 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.

Avvisningskoder 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 (utan 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.

Customer Portal-beteende

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.

Avbryt 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 uppsägning

Att ange eller rensa cancel_at_next_billing_date skickar ingen dedikerad webhook. Om du vill spåra en schemalagd uppsägning läser du cancel_at_next_billing_date från API-svaret eller från nästa subscription.updated-payload.
Om du vill skilja On-Demand-uppsägningar från uppsägningar av schemalagda prenumerationer i din handler kontrollerar du prenumerationens on_demand-flagga när du bearbetar webhooken.

Spåra resultat med webhooks

Implementera webhook-hantering för att spåra kundresan. Se Webhooks.
  • subscription.active: Mandate auktoriserat och prenumerationen aktiverad
  • subscription.failed: Skapandet misslyckades (t.ex. ett misslyckat mandate)
  • subscription.on_hold: Prenumerationen sattes på hold (t.ex. obetalt tillstånd)
  • subscription.cancelled: Prenumerationen är helt uppsagd (se Uppsägning)
  • 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 kan du läsa 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 en liten product_price (t.ex. 100) och kontrollera att du får payment.succeeded.
3

Go live

Byt till din live-API-nyckel när du har validerat händelser och interna tillståndsuppdateringar.

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 bekräftar du 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 26 september 2026