Change Plan API
Plan Change Preview
Integration Guide
What Is a Subscription Upgrade or Downgrade?
Change a customer’s subscription plan to move them between tiers, adjust quantity for seat-based products, or migrate to a new product. The API automatically calculates prorations and charges based on your chosen billing mode.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
- Credits the unused portion of the current cycle, prorated by time remaining
- Then charges a full cycle at the new plan — the new plan price is never prorated
- Net charge = full new cycle − (remaining fraction × full old cycle)
Implement the Change Plan API
prorated_immediately, full_immediately, difference_immediately o do_not_bill.null o inviare un array vuoto rimuove tutti i componenti aggiuntivi esistenti; includi quindi i componenti aggiuntivi attuali per mantenerli.prevent_change: Mantieni l’abbonamento sul piano attuale finché il pagamento non va a buon fineapply_change(predefinito): Applica immediatamente la modifica del piano indipendentemente dall’esito del pagamento
allow_plan_change_via_payment_link capability (Settings → Subscriptions → Collect Plan Change Payments by Payment Link), effective_at: immediately, and on_payment_failure: prevent_change. See Collecting Payment via a Checkout Link. Ignored by the preview route.subscription_id, payment_id e status. Richiede collect_via_payment_link: true; in caso contrario, la richiesta fallisce con 422. Consulta Reindirizzamento del cliente dopo il pagamento.409. Consulta Sostituzione di un link di pagamento in sospeso. Ignorato dalla route di anteprima.- Non fornito /
null— gli sconti esistenti conpreserve_on_plan_change=truevengono mantenuti, se applicabili al nuovo prodotto. [](array vuoto) — rimuove tutti gli sconti esistenti dall’abbonamento.["CODE_A", "CODE_B", ...]— sostituisce gli sconti esistenti con questo set stacked.
discount_codes. Questo campo continua a funzionare per la compatibilità con le versioni precedenti, ma non può essere combinato con discount_codes nella stessa richiesta.immediately(predefinito): Applica subito la modifica del pianonext_billing_date: Pianifica la modifica per la prossima data di fatturazione. Il cliente mantiene il piano attuale fino alla fine del periodo di fatturazione. Usalo per i downgrade, così i clienti mantengono i vantaggi del piano attuale fino alla fine del periodo di fatturazione.
Handle Webhook Events
subscription.active: Modifica del piano completata, abbonamento aggiornatosubscription.plan_changed: Piano dell’abbonamento modificato (upgrade/downgrade/aggiornamento dell’addon)subscription.on_hold: Addebito della modifica del piano non riuscito, rinnovi interrottipayment.succeeded: Addebito immediato della modifica del piano completatopayment.failed: Addebito immediato non riuscito
Update Your Application State
- Concedi/revoca le funzionalità in base al nuovo piano
- Aggiorna il dashboard del cliente con i dettagli del nuovo piano
- Invia email di conferma sulle modifiche del piano
- Registra le modifiche di fatturazione per scopi di audit
Test and Monitor
- Testa tutte le modalità di prorazione con scenari diversi
- Verifica che la gestione dei webhook funzioni correttamente
- Monitora i tassi di successo delle modifiche del piano
- Configura avvisi per le modifiche del piano non riuscite
Anteprima delle modifiche del piano
Prima di confermare una modifica del piano, usa l’API Preview per mostrare ai clienti esattamente quanto verrà loro addebitato:- Node.js SDK
- Python SDK
immediate_charge.summary, customer_credits è la variazione netta del saldo crediti del cliente, nella valuta indicata da customer_credits_currency. Questa è la valuta del portafoglio crediti del cliente, che corrisponde alla valuta dell’abbonamento. Può differire da currency del riepilogo, che si applica a total_amount e tax. Ad esempio, un cliente che paga in INR per un abbonamento in USD visualizza i crediti in USD.API Change Plan
Usa l’API Change Plan per modificare prodotto, quantità e comportamento della prorazione per un abbonamento attivo.Esempi rapidi
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
200 OK — prima che qualsiasi addebito sia stato effettivamente regolato. Il contenuto del body (ChangePlanResponse) dipende dal metodo di riscossione della modifica:
collect_via_payment_link, l’abbonamento rimane sul piano attuale finché il cliente non completa il pagamento.Conferma l’esito tramite webhook (payment.succeeded, payment.failed, subscription.plan_changed) oppure rileggi l’abbonamento con GET /subscriptions/{subscription_id} — per il caso del link di pagamento, consulta Cosa succede mentre il link non è pagato.Riscossione del pagamento tramite un link di checkout
Per impostazione predefinita, una modifica immediata del piano addebita direttamente il metodo di pagamento salvato dell’abbonamento. Impostacollect_via_payment_link: true per inviare il cliente a una pagina di checkout ospitata, utile quando non esiste un metodo di pagamento salvato o vuoi che il cliente confermi attivamente il nuovo prezzo.
Requisiti
collect_via_payment_link: true ha esito positivo solo quando sono soddisfatte tutte le condizioni seguenti; in caso contrario, la richiesta fallisce con 422:
- L’azienda ha abilitata la funzionalità
allow_plan_change_via_payment_link(Impostazioni → Abbonamenti → Raccogli i pagamenti delle modifiche del piano tramite link di pagamento). effective_atèimmediately(il valore predefinito). Una modifica pianificata (next_billing_date) non richiede mai una pagina di checkout.- La richiesta imposta
on_payment_failure: prevent_change. Unapply_changeesplicito fallisce con422.
collect_via_payment_link si applica a qualsiasi modifica immediata che comporti un addebito, inclusi i downgrade, purché siano soddisfatti i requisiti precedenti.payment_link e gli altri campi del checkout restituiscono null e la modifica viene applicata immediatamente. Questo non è un 422. Chiama prima Preview Plan Change per verificare l’importo prima di richiedere un link.
- Node.js SDK
- Python SDK
- HTTP
Cosa succede mentre il link non è pagato
- L’abbonamento rimane sul piano attuale:
product_id,recurring_pre_tax_amountenext_billing_daterimangono tutti invariati finché il link non viene pagato. - Un’ulteriore richiesta
change-planviene rifiutata con409 PendingPlanChangeExistsmentre il link è in sospeso. Per sostituire la modifica in sospeso, invia la nuova richiesta concancel_older_payment_link: true. Consulta Sostituzione di un link di pagamento in sospeso. - Per riprovare dopo un pagamento rifiutato, chiama nuovamente
change-planper ottenere un nuovo link. - Se il link non viene mai pagato, smette di funzionare dopo
expires_on; l’abbonamento diventa automaticamente disponibile per accettare una nuova richiesta di modifica del piano poco dopo. - Se esisteva già una modifica pianificata e la sostituisci con
cancel_scheduled_change_plan: true, la pianificazione originale rimane attiva mentre il link non è pagato e viene annullata solo dopo il pagamento del link, nella stessa transazione che applica il nuovo piano.
Reindirizzamento del cliente dopo il pagamento
Impostareturn_url per rimandare il cliente al tuo sito dopo il pagamento del link:
return_url con questi parametri di query:
return_url richiede collect_via_payment_link: true. Senza di esso, la richiesta fallisce con 422.
Sostituzione di un link di pagamento in sospeso
Se il cliente abbandona il checkout senza pagare, impostacancel_older_payment_link: true nella richiesta change-plan successiva. Dodo Payments annulla il link non pagato e la nuova modifica del piano sostituisce quella in sospeso. Il link annullato non accetta più pagamenti, nemmeno in una pagina di checkout già aperta.
change-plan emette la propria fattura. La modifica del piano sostituita e la relativa fattura vengono annullate. Se non è in sospeso alcuna modifica del piano, cancel_older_payment_link non ha effetto.
Gestione degli addon
Quando modifichi i piani degli abbonamenti, puoi modificare anche gli addon:Applicazione dei codici sconto
Applica uno o più codici sconto stacked durante la modifica dei piani degli abbonamenti (massimo 20, applicati nell’ordine dell’array):- Node.js SDK
- Python SDK
- HTTP
Comportamento degli sconti durante la modifica del piano
discount_code di questo endpoint è deprecato, ma continua a funzionare per la compatibilità con le versioni precedenti; le integrazioni esistenti non devono essere modificate immediatamente. Non può essere combinato con discount_codes nella stessa richiesta. Esegui la migrazione al formato array quando è opportuno.Modalità di prorazione
Scegli come addebitare il cliente quando modifichi il piano:prorated_immediately
- Accredita la parte inutilizzata del ciclo attuale — piano base, quantità e addon — calcolata proporzionalmente al tempo rimanente
- Quindi addebita un ciclo completo del nuovo piano, della nuova quantità e dei nuovi addon. L’addebito non viene mai calcolato proporzionalmente
- Addebito immediato netto = (nuovo ciclo completo) − (frazione rimanente × vecchio ciclo completo)
- Se il credito supera l’addebito del nuovo ciclo (caso comune nei downgrade), la differenza viene mantenuta come credito associato all’abbonamento per i rinnovi futuri
- Se l’abbonamento è in prova, addebita immediatamente e passa ora al nuovo piano
full_immediately
- Addebita immediatamente l’intero importo del nuovo piano
- Ignora il tempo rimanente del vecchio piano: nessun credito per il ciclo attuale
prorated_immediately e dai downgrade che usano difference_immediately sono associati all’abbonamento e distinti dalle disponibilità di Credit-Based Billing. Vengono applicati automaticamente ai rinnovi futuri dello stesso abbonamento e non sono trasferibili tra abbonamenti.difference_immediately
- Upgrade: addebita immediatamente la differenza di prezzo tra il vecchio e il nuovo piano
- Downgrade: aggiunge il valore rimanente come credito interno all’abbonamento e lo applica automaticamente ai rinnovi
do_not_bill
- Non vengono calcolati addebiti o crediti
- Il cliente passa immediatamente al nuovo piano senza alcun adeguamento di fatturazione
- Il ciclo di fatturazione rimane invariato
- Ideale per migrazioni per cortesia, passaggi a piani gratuiti o per assorbire differenze di costo
Scenari di esempio
Usa sempre questi numeri canonici:- Piano attuale: Basic a $30/mese
- Destinazione dell’upgrade: Pro a $80/mese
- Destinazione del downgrade (da Pro): Starter a $20/mese
- Ciclo di fatturazione: 30 giorni, iniziato il 1 gennaio
- La modifica del piano avviene il 16 gennaio (15 giorni rimanenti, 15 giorni utilizzati)
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
Come ogni modalità elabora la fatturazione
Gestione dei pagamenti non riusciti
Controlla cosa succede quando il pagamento di una modifica del piano non va a buon fine usando il parametroon_payment_failure.
Modalità di mancato pagamento
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- La modifica del piano viene contrassegnata come “in sospeso”
- Il cliente mantiene l’accesso al piano attuale
- L’abbonamento passa allo stato
activesolo dopo il pagamento completato - Utile quando vuoi assicurarti del pagamento prima di concedere funzionalità avanzate
on_payment_failure usa l’impostazione predefinita a livello aziendale configurata nel dashboard.Quando usare ciascuna modalità
Impostazioni predefinite aziendali e di riscossione
Imposta il comportamento predefinito per upgrade e downgrade a livello aziendale in Impostazioni → Abbonamenti. Queste impostazioni si applicano a tutte le modifiche del piano dal customer portal e possono essere sovrascritte per ogni raccolta di prodotti. Esistono impostazioni predefinite separate per upgrade e downgrade:Ordine di risoluzione
Per una determinata modifica del piano, ogni impostazione viene risolta nel seguente ordine:Gestione dei webhook
Monitora lo stato dell’abbonamento tramite webhook per confermare le modifiche del piano e i pagamenti.Tipi di evento da gestire
subscription.active: abbonamento attivatosubscription.plan_changed: piano dell’abbonamento modificato (upgrade/downgrade/modifiche degli addon)subscription.on_hold: addebito non riuscito, rinnovi interrottisubscription.renewed: rinnovo completatopayment.succeeded: pagamento della modifica del piano o del rinnovo completatopayment.failed: pagamento non riuscito
Verifica delle firme e gestione degli intent
- Next.js Route Handler
- Express.js
Best practice
Strategia per le modifiche del piano
- Testa accuratamente: testa sempre le modifiche del piano in modalità test prima della produzione
- Scegli con attenzione la prorazione: seleziona la modalità di prorazione in linea con il tuo modello aziendale
- Gestisci elegantemente gli errori: implementa una gestione degli errori e una logica di retry adeguate
- Monitora i tassi di successo: monitora i tassi di successo/fallimento delle modifiche del piano e analizza i problemi
Implementazione dei webhook
- Verifica le firme: convalida sempre le firme dei webhook per garantirne l’autenticità
- Implementa l’idempotenza: gestisci correttamente gli eventi webhook duplicati
- Elabora in modo asincrono: non bloccare le risposte dei webhook con operazioni pesanti
- Registra tutto: mantieni log dettagliati per il debug e gli audit
Esperienza utente
- Comunica chiaramente: informa i clienti sulle modifiche di fatturazione e sulle tempistiche
- Fornisci conferme: invia email di conferma per le modifiche del piano completate
- Gestisci i casi limite: considera periodi di prova, prorazioni e pagamenti non riusciti
- Aggiorna subito l’interfaccia: rifletti le modifiche del piano nell’interfaccia della tua applicazione
Problemi comuni e soluzioni
Risolvi i problemi tipici riscontrati durante le modifiche dei piani degli abbonamenti:Charge created but subscription not updated
Charge created but subscription not updated
- L’elaborazione del webhook non è riuscita o è stata ritardata
- Lo stato dell’applicazione non è stato aggiornato dopo la ricezione dei webhook
- Problemi con la transazione del database durante l’aggiornamento dello stato
- Implementa la gestione dei webhook con logica di retry
- Usa operazioni idempotenti per gli aggiornamenti dello stato
- Aggiungi il monitoraggio per rilevare e segnalare gli eventi webhook mancanti
- Verifica che l’endpoint webhook sia accessibile e risponda correttamente
Credits not applied after downgrade
Credits not applied after downgrade
- Aspettative sulla modalità di prorazione: i downgrade accreditano la differenza completa del prezzo del piano con
difference_immediately, mentreprorated_immediatelyaccredita il tempo inutilizzato del vecchio ciclo e poi addebita un ciclo completo al nuovo piano; quindi un saldo crediti rimane solo quando tale credito supera il prezzo del nuovo piano - I crediti sono specifici dell’abbonamento e non vengono trasferiti tra abbonamenti
- Il saldo dei crediti non è visibile nel dashboard del cliente
- Usa
difference_immediatelyper i downgrade quando vuoi crediti automatici - Spiega ai clienti che i crediti vengono applicati ai rinnovi futuri dello stesso abbonamento
- Implementa il customer portal per mostrare i saldi dei crediti
- Controlla l’anteprima della fattura successiva per visualizzare i crediti applicati
Webhook signature verification fails
Webhook signature verification fails
- Chiave segreta del webhook errata
- Body della richiesta originale modificato prima della verifica della firma
- Algoritmo di verifica della firma errato
- Verifica di usare il corretto
DODO_PAYMENTS_WEBHOOK_KEYdal dashboard - Leggi il body originale della richiesta prima di qualsiasi middleware di parsing JSON
- Usa la libreria standard di verifica dei webhook per la tua piattaforma
- Testa la verifica della firma dei webhook nell’ambiente di sviluppo
Plan change fails with 422 error
Plan change fails with 422 error
- ID abbonamento o ID prodotto non valido
- Abbonamento non nello stato attivo
- Parametri obbligatori mancanti
- Prodotto non disponibile per le modifiche del piano
- Verifica che l’abbonamento esista e sia attivo
- Controlla che l’ID prodotto sia valido e disponibile
- Assicurati che siano forniti tutti i parametri obbligatori
- Consulta la documentazione API per i requisiti dei parametri
Immediate charge fails during plan change
Immediate charge fails during plan change
- Fondi insufficienti sul metodo di pagamento del cliente
- Metodo di pagamento scaduto o non valido
- La banca ha rifiutato la transazione
- Il rilevamento delle frodi ha bloccato l’addebito
- Gestisci correttamente gli eventi webhook
payment.failed - Informa il cliente che deve aggiornare il metodo di pagamento
- Implementa la logica di retry per gli errori temporanei
- Valuta la possibilità di consentire modifiche del piano con addebiti immediati non riusciti
Subscription on hold after plan change
Subscription on hold after plan change
on_holdCosa succede:
Quando l’addebito della modifica del piano non va a buon fine, l’abbonamento viene automaticamente impostato sullo stato on_hold. L’abbonamento non verrà rinnovato automaticamente finché il metodo di pagamento non viene aggiornato.Soluzione: aggiorna il metodo di pagamento per riattivare l’abbonamentoPer riattivare un abbonamento dallo stato on_hold dopo una modifica del piano non riuscita:- Aggiorna il metodo di pagamento usando l’API Update Payment Method
- Creazione automatica dell’addebito: l’API crea automaticamente un addebito per gli importi ancora dovuti
- Generazione della fattura: viene generata una fattura per l’addebito
- Elaborazione del pagamento: il pagamento viene elaborato usando il nuovo metodo di pagamento
- Riattivazione: dopo il pagamento completato, l’abbonamento viene riattivato allo stato
active
subscription.on_hold: abbonamento sospeso (ricevuto quando l’addebito della modifica del piano non va a buon fine)payment.succeeded: pagamento degli importi ancora dovuti completato (dopo l’aggiornamento del metodo di pagamento)subscription.active: abbonamento riattivato dopo il pagamento completato
- Informa immediatamente i clienti quando l’addebito della modifica del piano non va a buon fine
- Fornisci istruzioni chiare su come aggiornare il metodo di pagamento
- Monitora gli eventi webhook per seguire lo stato della riattivazione
- Valuta l’implementazione di una logica di retry automatica per i pagamenti temporaneamente non riusciti
Update Payment Method API Reference
Test dell’implementazione
Testa accuratamente l’implementazione della modifica del piano dell’abbonamento:Set up test environment
- Usa chiavi API di test e prodotti di test
- Crea abbonamenti di test con diversi tipi di piano
- Configura un endpoint webhook di test
- Configura il monitoraggio e la registrazione dei log
Test different proration modes
- Testa
prorated_immediatelycon diverse posizioni nel ciclo di fatturazione - Testa
difference_immediatelyper upgrade e downgrade - Testa
full_immediatelyper reimpostare i cicli di fatturazione - Testa
do_not_billper passaggi di piano senza addebiti o crediti - Verifica che i calcoli dei crediti siano corretti
Test webhook handling
- Verifica che vengano ricevuti tutti gli eventi webhook pertinenti
- Testa la verifica delle firme dei webhook
- Gestisci correttamente gli eventi webhook duplicati
- Testa gli scenari di errore nell’elaborazione dei webhook
Test error scenarios
- Testa con ID abbonamento non validi
- Testa con metodi di pagamento scaduti
- Testa errori di rete e timeout
- Testa con fondi insufficienti
Monitor in production
- Configura avvisi per le modifiche del piano non riuscite
- Monitora i tempi di elaborazione dei webhook
- Monitora i tassi di successo delle modifiche del piano
- Esamina i ticket dell’assistenza clienti relativi ai problemi delle modifiche del piano
Gestione degli errori
Gestisci correttamente gli errori API comuni nella tua implementazione:Codici di stato HTTP
200 OK
200 OK
ChangePlanResponse con payment_id, payment_link, client_secret e expires_on. Tutti e quattro sono nullable, quindi il body viene serializzato come {} per una modifica ordinaria off-session; vengono valorizzati per una richiesta collect_via_payment_link completata, che restituisce i riferimenti al checkout. Consulta Riscossione del pagamento tramite un link di checkout. Se on_payment_failure=prevent_change, la modifica del piano rimane in sospeso finché il pagamento non va a buon fine.400 Bad Request
400 Bad Request
409 Conflict
409 Conflict
PendingPlanChangeExists). Per una modifica pianificata, annullala con DELETE /subscriptions/{subscription_id}/change-plan/scheduled prima di inviarne una nuova. Per una modifica tramite link di pagamento in sospeso, invia la nuova richiesta con cancel_older_payment_link: true per sostituirla. Consulta Sostituzione di un link di pagamento in sospeso.Con cancel_older_payment_link: true, un 409 significa che il cliente sta pagando ora il link precedente (PLAN_CHANGE_PAYMENT_IN_PROGRESS) o lo ha già pagato (PLAN_CHANGE_PAYMENT_ALREADY_COMPLETED).422 Unprocessable Entity
422 Unprocessable Entity
collect_via_payment_link: l’azienda non ha abilitato la funzionalità, effective_at non è immediately oppure on_payment_failure non è prevent_change. Consulta Requisiti. Un ID abbonamento inesistente o non appartenente al tuo account restituisce 404 con il codice NOT_FOUND.500 Internal Server Error
500 Internal Server Error
Formato della risposta di errore
Gli errori restituiscono un body JSON con uncode e un message leggibile dall’utente:
Passaggi successivi
- Consulta l’API Change Plan
- Esplora Credit-Based Billing
- Implementa avvisi per
subscription.on_hold - Consulta la Guida all’integrazione dei webhook