Change Plan API
Plan Change Preview
Integration Guide
What is a subscription upgrade or downgrade?
Changing plans lets you move a customer between subscription tiers or quantities. Use it to:- Align pricing with usage or features
- Move from monthly to annual (or vice versa)
- Adjust quantity for seat-based products
When to use plan changes
- Upgrade when a customer needs more features, usage, or seats
- Downgrade when usage decreases
- Migrate users to a new product or price without cancelling their subscription
Plan Change Flow
Prerequisites
Before implementing subscription plan changes, ensure you have:- A Dodo Payments merchant account with active subscription products
- API credentials (API key and webhook secret key) from the dashboard
- An existing active subscription to modify
- Webhook endpoint configured to handle subscription events
Step-by-Step Implementation Guide
Follow this comprehensive guide to implement subscription plan changes in your application:Understand Plan Change Requirements
- Which subscription products can be changed to which others
- What proration mode fits your business model
- How to handle failed plan changes gracefully
- Which webhook events to track for state management
Choose Your Proration Strategy
- prorated_immediately
- difference_immediately
- full_immediately
- do_not_bill
- Calculates exact prorated amount based on remaining cycle time
- Charges a prorated amount based on unused time remaining in the cycle
- Provides transparent billing to customers
Implement the Change Plan API
prorated_immediately, full_immediately, difference_immediately, or do_not_bill.prevent_change: Keep subscription on current plan until payment succeedsapply_change(default): Apply plan change immediately regardless of payment outcome
allow_plan_change_via_payment_link-funktion (Settings → Subscriptions → Collect Plan Change Payments by Payment Link), effective_at: immediately och on_payment_failure: prevent_change. Se Samla in betalning via en checkout-länk.Ignoreras av preview-routen.- Inte angivet /
null— befintliga rabatter medpreserve_on_plan_change=truebevaras om de gäller för den nya produkten. [](tom array) — tar bort alla befintliga rabatter från prenumerationen.["CODE_A", "CODE_B", ...]— ersätter alla befintliga rabatter med denna staplade uppsättning.
discount_codes för nya integrationer. Fältet fungerar fortfarande för bakåtkompatibilitet, men kan inte kombineras med discount_codes i samma begäran.immediately(standard): Tillämpa planändringen omedelbartnext_billing_date: Schemalägg ändringen till nästa faktureringsdatum. Kunden behåller sin aktuella plan tills faktureringsperioden är slut.
next_billing_date för nedgraderingar så att kunderna behåller förmånerna från sin aktuella plan tills faktureringsperioden är slut.Handle Webhook Events
subscription.active: Planändringen lyckades, prenumerationen uppdateradessubscription.plan_changed: Prenumerationsplanen ändrades (uppgradering/nedgradering/uppdatering av addon)subscription.on_hold: Debiteringen för planändringen misslyckades, förnyelser stoppadespayment.succeeded: Den omedelbara debiteringen för planändringen lyckadespayment.failed: Den omedelbara debiteringen misslyckades
Update Your Application State
- Ge eller återkalla funktioner baserat på den nya planen
- Uppdatera kundpanelen med information om den nya planen
- Skicka bekräftelsemejl om planändringar
- Logga faktureringsändringar för revisionsändamål
Test and Monitor
- Testa alla prorationslägen med olika scenarier
- Verifiera att webhook-hanteringen fungerar korrekt
- Övervaka andelen lyckade planändringar
- Konfigurera aviseringar för misslyckade planändringar
Förhandsgranska planändringar
Innan du genomför en planändring kan du använda Preview API för att visa kunderna exakt vad de kommer att debiteras:- Node.js SDK
- Python SDK
Change Plan API
Använd Change Plan API för att ändra produkt, kvantitet och prorationsbeteende för en aktiv prenumeration.Snabba exempel
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
200 OK omedelbart — innan någon debitering faktiskt har slutförts. Vad body (ChangePlanResponse) innehåller beror på hur ändringen samlades in:
collect_via_payment_link-begäran fastställs resultatet senare och asynkront — svaret ger dig endast en checkout-länk, prenumerationen ligger kvar på sin aktuella plan och inget är känt om resultatet förrän kunden faktiskt slutför betalningen via länken.Oavsett vilket ska du inte dra slutsatser om resultatet från detta svar. Bekräfta det via webhook (payment.succeeded, payment.failed, subscription.plan_changed) eller genom att läsa prenumerationen igen med GET /subscriptions/{subscription_id} — se Vad händer medan länken är obetald specifikt för fallet med betalningslänk.Samla in betalning via en checkout-länk
Som standard debiterar en omedelbar planändring prenumerationens sparade betalningsmetod direkt. Angecollect_via_payment_link: true för att i stället skicka kunden till en hostad checkout-sida — användbart när det inte finns någon sparad betalningsmetod som du får debitera utanför sessionen, eller när du vill att kunden aktivt ska bekräfta det nya priset.
Krav
collect_via_payment_link: true lyckas endast när alla följande villkor är uppfyllda — annars misslyckas begäran med 422:
- Företaget har
allow_plan_change_via_payment_link-funktionen aktiverad (Settings → Subscriptions → Collect Plan Change Payments by Payment Link). effective_atärimmediately(standardvärdet). En schemalagd ändring (next_billing_date) behöver aldrig en checkout-sida, eftersom inget debiteras förrän ändringen tillämpas.- Den effektiva
on_payment_failurelöses tillprevent_change. Du behöver inte skicka den uttryckligen — om företagets standardvärde (se Företags- och insamlingsstandarder nedan) redan ärprevent_changeuppfyller det också detta villkor när fältet utelämnas. Ett uttryckligtapply_change, eller ett löst standardvärde påapply_change, misslyckas med422.
collect_via_payment_link är inte begränsad till uppgraderingar — den gäller alla omedelbara ändringar som leder till en debitering, inklusive nedgraderingar, så länge kraven ovan är uppfyllda.proration_billing_mode: do_not_bill eller ett annat läge som råkar ge noll netto den här cykeln — finns det inget att lägga på en checkout-sida. Ingen betalningslänk utfärdas, payment_link och liknande returneras som null, och ändringen tillämpas omedelbart, precis som den skulle ha gjort utan collect_via_payment_link. Detta är inte ett 422; flaggan träder endast i kraft när det finns ett positivt belopp att samla in. Om du anger collect_via_payment_link generellt för planändringar i stället för enbart för tydliga uppgraderingar bör du först anropa Preview Plan Change och endast begära en länk när det förhandsgranskade beloppet är värt att samla in.
- Node.js SDK
- Python SDK
- HTTP
Vad händer medan länken är obetald
- Prenumerationen ligger kvar på sin aktuella plan —
product_id,recurring_pre_tax_amountochnext_billing_datepåverkas inte förrän länken har betalats. - En ytterligare
change-plan-begäran för samma prenumeration avvisas med409 PendingPlanChangeExistsmedan länken väntar. Avbryt en schemalagd ändring medDELETE /subscriptions/{subscription_id}/change-plan/scheduledvid behov, men den endpointen avbryter inte en väntande ändring via betalningslänk — endast en lyckad betalning eller länkens utgång gör det. - Kunden kan försöka betala med ett kort igen i samma checkout-session efter ett avslag; ett nytt
change-plan-anrop är inte rätt sätt att försöka igen. - Om länken aldrig betalas slutar den att fungera efter
expires_on— prenumerationen blir automatiskt tillgänglig för en ny begäran om planändring kort därefter. - Om en schemalagd ändring (
next_billing_date) redan fanns och du ersätter den medcancel_scheduled_change_plan: trueligger det ursprungliga schemat kvar medan länken är obetald och avbryts först när länken har betalats — i samma transaktion som tillämpar den nya planen.
Hantera addons
När du ändrar prenumerationsplaner kan du även ändra addons:Tillämpa rabattkoder
Du kan tillämpa en eller flera staplade rabattkoder när du ändrar prenumerationsplaner (högst 20, tillämpas i arrayordning). Detta är användbart när du erbjuder kampanjpriser vid uppgraderingar eller migreringar.- Node.js SDK
- Python SDK
- HTTP
Rabattbeteende vid planändring
discount_code för denna endpoint är föråldrat, men fungerar fortfarande för bakåtkompatibilitet — befintliga integrationer behöver inte ändras omedelbart. Det kan inte kombineras med discount_codes i samma begäran. Migrera till arrayformatet när det passar.Prorationslägen
Välj hur kunden ska faktureras när planer ändras:prorated_immediately
- Debiterar den proportionella skillnaden för den del av den aktuella cykeln som återstår
- Om kunden är i en provperiod debiteras kunden omedelbart och byter till den nya planen nu
- Nedgradering: kan skapa en proportionell kreditering som tillämpas på framtida förnyelser
full_immediately
- Debiterar hela beloppet för den nya planen omedelbart
- Tar inte hänsyn till återstående tid i den gamla planen
difference_immediately är knutna till prenumerationen och skiljer sig från förmåner inom Credit-Based Billing. De tillämpas automatiskt på framtida förnyelser av samma prenumeration och kan inte överföras mellan prenumerationer.difference_immediately
- Uppgradering: debiterar omedelbart prisskillnaden mellan den gamla och den nya planen
- Nedgradering: lägger till återstående värde som intern kredit på prenumerationen och tillämpar den automatiskt vid förnyelser
do_not_bill
- Inga debiteringar eller krediter beräknas
- Kunden byter omedelbart till den nya planen utan någon faktureringsjustering
- Faktureringscykeln förblir oförändrad
- Passar bäst för kostnadsfria migreringar, byten till gratisplaner eller när kostnadsskillnader tas bort
Exempelscenarier
Använd dessa kanoniska siffror konsekvent:- Aktuell plan: Basic på $30/månad
- Målplan för uppgradering: Pro på $80/månad
- Målplan för nedgradering (från Pro): Starter på $20/månad
- Faktureringscykel: 30 dagar, startade January 1
- Planändringen sker January 16 (15 dagar kvar, 15 dagar använda)
Upgrade: Basic ($30) → Pro ($80) with prorated_immediately
Upgrade: Basic ($30) → Pro ($80) with prorated_immediately
Downgrade: Pro ($80) → Starter ($20) with prorated_immediately
Downgrade: Pro ($80) → Starter ($20) with prorated_immediately
Upgrade: Basic ($30) → Pro ($80) with difference_immediately
Upgrade: Basic ($30) → Pro ($80) with difference_immediately
Downgrade: Pro ($80) → Starter ($20) with difference_immediately
Downgrade: Pro ($80) → Starter ($20) with difference_immediately
Upgrade: Basic ($30) → Pro ($80) with full_immediately
Upgrade: Basic ($30) → Pro ($80) with full_immediately
Mid-cycle upgrade with add-ons using prorated_immediately
Mid-cycle upgrade with add-ons using prorated_immediately
Så behandlar varje läge faktureringen
Hantera betalningsmisslyckanden
Styr vad som händer när en betalning för en planändring misslyckas med parameternon_payment_failure.
Lägen för betalningsmisslyckanden
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- Planändringen markeras som “pending”
- Kunden behåller åtkomsten till sin aktuella plan
- Prenumerationen övergår till tillståndet
activeförst efter en lyckad betalning - Användbart när du vill säkerställa betalning innan du ger tillgång till uppgraderade funktioner
on_payment_failure företagets standardinställning som konfigurerats i dashboarden.När ska varje läge användas?
Företags- och insamlingsstandarder
I stället för att skicka prorationsparametrar vid varje planändring kan du ange standardbeteende för uppgraderingar och nedgraderingar en gång på företagsnivå. Dessa standardvärden gäller för alla planändringar i kundportalen och kan åsidosättas per produktkollektion. Det finns separata standardvärden för uppgraderingar och nedgraderingar:Prioritetsordning
För en viss planändring löses varje inställning i denna ordning:Hantera webhooks
Spåra prenumerationens status via webhooks för att bekräfta planändringar och betalningar.Händelsetyper att hantera
subscription.active: prenumerationen aktiveradessubscription.plan_changed: prenumerationsplanen ändrades (uppgradering/nedgradering/ändringar av addon)subscription.on_hold: debiteringen misslyckades, förnyelser stoppadessubscription.renewed: förnyelsen lyckadespayment.succeeded: betalningen för planändringen eller förnyelsen lyckadespayment.failed: betalningen misslyckades
Verifiera signaturer och hantera intents
- Next.js Route Handler
- Express.js
Bästa praxis
Följ dessa rekommendationer för tillförlitliga planändringar av prenumerationer:Strategi för planändringar
- Testa noggrant: Testa alltid planändringar i testläge före produktion
- Välj proration med omsorg: Välj det prorationsläge som passar din affärsmodell
- Hantera fel på ett bra sätt: Implementera korrekt felhantering och logik för nya försök
- Övervaka lyckade ändringar: Spåra andelen lyckade och misslyckade planändringar och undersök problem
Webhook-implementering
- Verifiera signaturer: Validera alltid webhook-signaturer för att säkerställa äkthet
- Implementera idempotens: Hantera dubbla webhook-händelser på ett bra sätt
- Bearbeta asynkront: Blockera inte webhook-svar med tunga operationer
- Logga allt: Spara detaljerade loggar för felsökning och revisionsändamål
Användarupplevelse
- Kommunicera tydligt: Informera kunderna om faktureringsändringar och tidpunkter
- Ge bekräftelser: Skicka bekräftelsemejl för lyckade planändringar
- Hantera specialfall: Ta hänsyn till provperioder, prorering och misslyckade betalningar
- Uppdatera gränssnittet omedelbart: Återspegla planändringar i applikationens gränssnitt
Vanliga problem och lösningar
Lös typiska problem som uppstår vid ändringar av prenumerationsplaner:Charge created but subscription not updated
Charge created but subscription not updated
- Webhook-bearbetningen misslyckades eller fördröjdes
- Applikationens tillstånd uppdaterades inte efter mottagna webhooks
- Problem med databastransaktioner under tillståndsuppdateringen
- Implementera robust webhook-hantering med logik för nya försök
- Använd idempotenta åtgärder för tillståndsuppdateringar
- Lägg till övervakning för att upptäcka och avisera om missade webhook-händelser
- Verifiera att webhook-endpointen är tillgänglig och svarar korrekt
Credits not applied after downgrade
Credits not applied after downgrade
- Förväntningar på prorationsläget: nedgraderingar krediterar hela prisskillnaden med
difference_immediately, medanprorated_immediatelyskapar en proportionell kreditering baserat på återstående tid i cykeln - Krediter är prenumerationsspecifika och överförs inte mellan prenumerationer
- Kreditsaldot visas inte i kundpanelen
- Använd
difference_immediatelyför nedgraderingar när du vill ha automatiska krediter - Förklara för kunderna att krediter tillämpas på framtida förnyelser av samma prenumeration
- Implementera kundportalen så att kreditsaldon visas
- Kontrollera nästa fakturaförhandsgranskning för att se tillämpade krediter
Webhook signature verification fails
Webhook signature verification fails
- Felaktig webhook-hemlighet
- Rå request body ändrades före signaturverifieringen
- Fel algoritm för signaturverifiering
- Verifiera att du använder rätt
DODO_WEBHOOK_SECRETfrån dashboarden - Läs den råa request body innan någon middleware för JSON-parsning körs
- Använd standardbiblioteket för webhook-verifiering för din plattform
- Testa verifieringen av webhook-signaturer i utvecklingsmiljön
Plan change fails with 422 error
Plan change fails with 422 error
- Ogiltigt prenumerations-ID eller produkt-ID
- Prenumerationen är inte i aktivt tillstånd
- Obligatoriska parametrar saknas
- Produkten är inte tillgänglig för planändringar
- Verifiera att prenumerationen finns och är aktiv
- Kontrollera att produkt-ID:t är giltigt och tillgängligt
- Säkerställ att alla obligatoriska parametrar har angetts
- Läs API-dokumentationen för information om parameterkrav
Immediate charge fails during plan change
Immediate charge fails during plan change
- Otillräckliga medel på kundens betalningsmetod
- Betalningsmetoden har upphört att gälla eller är ogiltig
- Banken avvisade transaktionen
- Bedrägeridetektering blockerade debiteringen
- Hantera webhook-händelser av typen
payment.failedkorrekt - Informera kunden om att uppdatera betalningsmetoden
- Implementera logik för nya försök vid tillfälliga fel
- Överväg att tillåta planändringar trots misslyckade omedelbara debiteringar
Subscription on hold after plan change
Subscription on hold after plan change
on_holdVad händer:
När en debitering för en planändring misslyckas placeras prenumerationen automatiskt i tillståndet on_hold. Prenumerationen förnyas inte automatiskt förrän betalningsmetoden har uppdaterats.Lösning: Uppdatera betalningsmetoden för att återaktivera prenumerationenSå här återaktiverar du en prenumeration från tillståndet on_hold efter en misslyckad planändring:- Uppdatera betalningsmetoden med Update Payment Method API
- Automatisk skapelse av debitering: API:t skapar automatiskt en debitering för återstående belopp
- Generering av faktura: En faktura genereras för debiteringen
- Betalningshantering: Betalningen behandlas med den nya betalningsmetoden
- Återaktivering: Efter en lyckad betalning återaktiveras prenumerationen till tillståndet
active
subscription.on_hold: Prenumerationen sattes på hold (mottas när debiteringen för planändringen misslyckas)payment.succeeded: Betalningen för återstående belopp lyckades (efter uppdatering av betalningsmetoden)subscription.active: Prenumerationen återaktiverades efter en lyckad betalning
- Informera kunderna omedelbart när en debitering för en planändring misslyckas
- Ge tydliga instruktioner om hur betalningsmetoden uppdateras
- Övervaka webhook-händelser för att spåra återaktiveringsstatus
- Överväg att implementera automatisk logik för nya försök vid tillfälliga betalningsfel
Update Payment Method API Reference
Testa din implementering
Följ dessa steg för att testa implementeringen av planändringar för prenumerationer noggrant:Set up test environment
- Använd test-API-nycklar och testprodukter
- Skapa testprenumerationer med olika plantyper
- Konfigurera test-endpointen för webhooks
- Konfigurera övervakning och loggning
Test different proration modes
- Testa
prorated_immediatelymed olika positioner i faktureringscykeln - Testa
difference_immediatelyför uppgraderingar och nedgraderingar - Testa
full_immediatelyför att återställa faktureringscykler - Testa
do_not_billför planbyten utan debitering eller kreditering - Verifiera att krediterna beräknas korrekt
Test webhook handling
- Verifiera att alla relevanta webhook-händelser tas emot
- Testa verifiering av webhook-signaturer
- Hantera dubbla webhook-händelser på ett bra sätt
- Testa scenarier där webhook-bearbetningen misslyckas
Test error scenarios
- Testa med ogiltiga prenumerations-ID:n
- Testa med utgångna betalningsmetoder
- Testa nätverksfel och tidsgränser
- Testa med otillräckliga medel
Monitor in production
- Konfigurera aviseringar för misslyckade planändringar
- Övervaka webhook-bearbetningstider
- Spåra andelen lyckade planändringar
- Granska kundsupportärenden om problem med planändringar
Felhantering
Hantera vanliga API-fel på ett bra sätt i din implementering:HTTP-statuskoder
200 OK
200 OK
collect_via_payment_link-begäran, som returnerar checkout-handtag — se Samla in betalning via en checkout-länk. Om on_payment_failure=prevent_change förblir planändringen väntande tills betalningen lyckas.400 Bad Request
400 Bad Request
404 Not Found
404 Not Found
409 Conflict
409 Conflict
PendingPlanChangeExists). För en schemalagd ändring ska du avbryta den med DELETE /subscriptions/{subscription_id}/change-plan/scheduled innan du skickar en ny. För en väntande ändring via betalningslänk finns ingen endpoint för att avbryta den — prenumerationen accepterar en ny begäran om planändring när kunden betalar eller länken löper ut.422 Unprocessable Entity
422 Unprocessable Entity
collect_via_payment_link — företaget har inte funktionen aktiverad, effective_at är inte immediately, eller on_payment_failure är inte prevent_change. Se Krav.500 Internal Server Error
500 Internal Server Error
Format för felsvar
Nästa steg
- Granska Change Plan API
- Utforska Credit-Based Billing
- Implementera aviseringar för
subscription.on_hold - Läs vår guide för webhook-integration