Vai al contenuto principale

Cos’è un upgrade o downgrade dell’abbonamento?

Cambiare piano consente di spostare un cliente tra livelli o quantità di abbonamento. Usalo per:
  • Allineare i prezzi con l’uso o le funzionalità
  • Passare da mensile ad annuale (o viceversa)
  • Regolare la quantità per prodotti basati su posti
I cambiamenti di piano possono attivare un addebito immediato a seconda della modalità di proration che scegli.

Quando utilizzare i cambiamenti di piano

  • Aggiorna quando un cliente ha bisogno di più funzionalità, utilizzo o posti
  • Riduci quando l’uso diminuisce
  • Migra gli utenti a un nuovo prodotto o prezzo senza annullare il loro abbonamento

Requisiti

Prima di implementare i cambiamenti di piano di abbonamento, assicurati di avere:
  • Un account commerciante Dodo Payments con prodotti di abbonamento attivi
  • Credenziali API (chiave API e chiave segreta webhook) dal dashboard
  • Un abbonamento attivo esistente da modificare
  • Endpoint webhook configurato per gestire eventi di abbonamento
Per istruzioni dettagliate sulla configurazione, consulta la nostra Guida all’Integrazione.

Guida all’Implementazione Passo-Passo

Segui questa guida completa per implementare i cambiamenti di piano di abbonamento nella tua applicazione:
1

Comprendere i Requisiti per il Cambiamento di Piano

Prima di implementare, determina:
  • Quali prodotti di abbonamento possono essere cambiati con quali altri
  • Quale modalità di proration si adatta al tuo modello di business
  • Come gestire i cambiamenti di piano falliti in modo elegante
  • Quali eventi webhook monitorare per la gestione dello stato
Testa i cambiamenti di piano a fondo in modalità test prima di implementarli in produzione.
2

Scegli la Tua Strategia di Proration

Seleziona l’approccio di fatturazione che si allinea con le tue esigenze aziendali:
Ideale per: applicazioni SaaS che vogliono addebitare equamente per il tempo non utilizzato
  • Calcola l’importo esatto prorato in base al tempo rimanente del ciclo
  • Addebita un importo prorato in base al tempo non utilizzato rimanente nel ciclo
  • Fornisce una fatturazione trasparente ai clienti
3

Implementa l'API Cambia Piano

Usa l’API Cambia Piano per modificare i dettagli dell’abbonamento:
subscription_id
string
obbligatorio
L’ID dell’abbonamento attivo da modificare.
product_id
string
obbligatorio
Il nuovo ID prodotto a cui cambiare l’abbonamento.
quantity
integer
predefinito:"1"
Numero di unità per il nuovo piano (per prodotti basati su posti).
proration_billing_mode
string
obbligatorio
Come gestire la fatturazione immediata: prorated_immediately, full_immediately, o difference_immediately.
addons
array
Addon opzionali per il nuovo piano. Lasciando questo vuoto si rimuovono eventuali addon esistenti.
4

Gestisci gli Eventi Webhook

Configura la gestione dei webhook per monitorare gli esiti dei cambiamenti di piano:
  • subscription.active: Cambiamento di piano riuscito, abbonamento aggiornato
  • subscription.plan_changed: Piano di abbonamento cambiato (upgrade/downgrade/aggiornamento addon)
  • subscription.on_hold: Addebito per il cambiamento di piano fallito, abbonamento in pausa
  • payment.succeeded: Addebito immediato per il cambiamento di piano riuscito
  • payment.failed: Addebito immediato fallito
Verifica sempre le firme dei webhook e implementa un’elaborazione degli eventi idempotente.
5

Aggiorna lo Stato della Tua Applicazione

In base agli eventi webhook, aggiorna la tua applicazione:
  • Concedi/rimuovi funzionalità in base al nuovo piano
  • Aggiorna il dashboard del cliente con i dettagli del nuovo piano
  • Invia email di conferma sui cambiamenti di piano
  • Registra le modifiche di fatturazione per scopi di audit
6

Testa e Monitora

Testa a fondo la tua implementazione:
  • Testa tutte le modalità di proration con diversi scenari
  • Verifica che la gestione dei webhook funzioni correttamente
  • Monitora i tassi di successo dei cambiamenti di piano
  • Configura avvisi per i cambiamenti di piano falliti
La tua implementazione del cambiamento di piano di abbonamento è ora pronta per l’uso in produzione.

Anteprima dei Cambiamenti di Piano

Prima di confermare un cambiamento di piano, utilizza l’API Anteprima per mostrare ai clienti esattamente quanto verrà addebitato:
const preview = await client.subscriptions.previewChangePlan('sub_123', {
  product_id: 'prod_pro',
  quantity: 1,
  proration_billing_mode: 'prorated_immediately'
});

// Show customer the charge before confirming
console.log('Immediate charge:', preview.immediate_charge.summary);
console.log('New plan details:', preview.new_plan);
Utilizza l’API di anteprima per costruire finestre di conferma che mostrano ai clienti l’importo esatto che verrà addebitato prima che confermino un cambiamento di piano.

API Cambia Piano

Utilizza l’API Cambia Piano per modificare prodotto, quantità e comportamento di proration per un abbonamento attivo.

Esempi di avvio rapido

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // defaults to 'live_mode'
});

async function changePlan() {
  const result = await client.subscriptions.changePlan('sub_123', {
    product_id: 'prod_new',
    quantity: 3,
    proration_billing_mode: 'prorated_immediately',
  });
  console.log(result.status, result.invoice_id, result.payment_id);
}

changePlan();
Success
{
  "status": "processing",
  "subscription_id": "sub_123",
  "invoice_id": "inv_789",
  "payment_id": "pay_456",
  "proration_billing_mode": "prorated_immediately"
}
Campi come invoice_id e payment_id vengono restituiti solo quando viene creato un addebito immediato e/o una fattura durante il cambiamento di piano. Fai sempre affidamento sugli eventi webhook (es. payment.succeeded, subscription.plan_changed) per confermare gli esiti.
Se l’addebito immediato fallisce, l’abbonamento potrebbe passare a subscription.on_hold fino a quando il pagamento non riesce.

Gestione degli Addon

Quando cambi i piani di abbonamento, puoi anche modificare gli addon:
// Add addons to the new plan
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_new',
  quantity: 1,
  proration_billing_mode: 'difference_immediately',
  addons: [
    { addon_id: 'addon_123', quantity: 2 }
  ]
});

// Remove all existing addons
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_new',
  quantity: 1,
  proration_billing_mode: 'difference_immediately',
  addons: [] // Empty array removes all existing addons
});
Gli addon sono inclusi nel calcolo della proration e verranno addebitati secondo la modalità di proration selezionata.

Modalità di Proration

Scegli come addebitare il cliente quando cambi piano:

prorated_immediately

  • Addebita per la differenza parziale nel ciclo corrente
  • Se in prova, addebita immediatamente e passa al nuovo piano ora
  • Downgrade: può generare un credito prorato applicato ai rinnovi futuri

full_immediately

  • Addebita l’importo totale del nuovo piano immediatamente
  • Ignora il tempo rimanente dal vecchio piano
I crediti creati dai downgrade utilizzando difference_immediately sono specifici per l’abbonamento e distinti dai Crediti Cliente. Si applicano automaticamente ai rinnovi futuri dello stesso abbonamento e non sono trasferibili tra abbonamenti.

difference_immediately

  • Upgrade: addebita immediatamente la differenza di prezzo tra i vecchi e i nuovi piani
  • Downgrade: aggiungi il valore rimanente come credito interno all’abbonamento e applicalo automaticamente ai rinnovi

Scenari di Esempio

await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_pro',
  quantity: 1,
  proration_billing_mode: 'difference_immediately'
})
// Immediate charge: $50
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_starter',
  quantity: 1,
  proration_billing_mode: 'difference_immediately'
})
// Credit added: $30 (auto-applied to future renewals for this subscription)
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_new',
  quantity: 1,
  proration_billing_mode: 'prorated_immediately'
})
// Immediate prorated charge based on remaining days in cycle
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_new',
  quantity: 1,
  proration_billing_mode: 'full_immediately'
})
// Immediate full charge for new plan; no credits calculated
Scegli prorated_immediately per una contabilità equa; scegli full_immediately per riavviare la fatturazione; usa difference_immediately per upgrade semplici e credito automatico sui downgrade.

Gestione dei webhook

Monitora lo stato dell’abbonamento tramite webhook per confermare i cambiamenti di piano e i pagamenti.

Tipi di eventi da gestire

  • subscription.active: abbonamento attivato
  • subscription.plan_changed: piano di abbonamento cambiato (upgrade/downgrade/cambiamenti addon)
  • subscription.on_hold: addebito fallito, abbonamento in pausa
  • subscription.renewed: rinnovo riuscito
  • payment.succeeded: pagamento per cambiamento di piano o rinnovo riuscito
  • payment.failed: pagamento fallito
Ti consigliamo di guidare la logica aziendale dagli eventi di abbonamento e di utilizzare gli eventi di pagamento per conferma e riconciliazione.

Verifica le firme e gestisci le intenzioni

import { NextRequest, NextResponse } from 'next/server';

export async function POST(req) {
  const webhookId = req.headers.get('webhook-id');
  const webhookSignature = req.headers.get('webhook-signature');
  const webhookTimestamp = req.headers.get('webhook-timestamp');
  const secret = process.env.DODO_WEBHOOK_SECRET;

  const payload = await req.text();
  // verifySignature is a placeholder – in production, use a Standard Webhooks library
  const { valid, event } = await verifySignature(
    payload,
    { id: webhookId, signature: webhookSignature, timestamp: webhookTimestamp },
    secret
  );
  if (!valid) return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });

  switch (event.type) {
    case 'subscription.active':
      // mark subscription active in your DB
      break;
    case 'subscription.plan_changed':
      // refresh entitlements and reflect the new plan in your UI
      break;
    case 'subscription.on_hold':
      // notify user to update payment method
      break;
    case 'subscription.renewed':
      // extend access window
      break;
    case 'payment.succeeded':
      // reconcile payment for plan change
      break;
    case 'payment.failed':
      // log and alert
      break;
    default:
      // ignore unknown events
      break;
  }

  return NextResponse.json({ received: true });
}
Per schemi di payload dettagliati, consulta i payload dei webhook di abbonamento e i payload dei webhook di pagamento.

Migliori Pratiche

Segui queste raccomandazioni per cambiamenti di piano di abbonamento affidabili:

Strategia di Cambiamento di Piano

  • Testa a fondo: Testa sempre i cambiamenti di piano in modalità test prima della produzione
  • Scegli la proration con attenzione: Seleziona la modalità di proration che si allinea con il tuo modello di business
  • Gestisci i fallimenti in modo elegante: Implementa una corretta gestione degli errori e logica di ripetizione
  • Monitora i tassi di successo: Monitora i tassi di successo/fallimento dei cambiamenti di piano e indaga sui problemi

Implementazione dei Webhook

  • Verifica le firme: Verifica sempre le firme dei webhook per garantire l’autenticità
  • Implementa l’idempotenza: Gestisci gli eventi webhook duplicati in modo elegante
  • Elabora in modo asincrono: Non bloccare le risposte dei webhook con operazioni pesanti
  • Registra tutto: Mantieni registri dettagliati per il debug e scopi di audit

Esperienza Utente

  • Comunica chiaramente: Informa i clienti sui cambiamenti di fatturazione e sui tempi
  • Fornisci conferme: Invia email di conferma per i cambiamenti di piano riusciti
  • Gestisci i casi limite: Considera i periodi di prova, le proration e i pagamenti falliti
  • Aggiorna immediatamente l’interfaccia utente: Riflette i cambiamenti di piano nella tua interfaccia applicativa

Problemi Comuni e Soluzioni

Risolvi i problemi tipici riscontrati durante i cambiamenti di piano di abbonamento:
Sintomi: La chiamata API ha successo ma l’abbonamento rimane sul vecchio pianoCause comuni:
  • Elaborazione del webhook fallita o ritardata
  • Stato dell’applicazione non aggiornato dopo aver ricevuto i webhook
  • Problemi di transazione del database durante l’aggiornamento dello stato
Soluzioni:
  • Implementa una gestione robusta dei webhook con logica di ripetizione
  • Usa operazioni idempotenti per gli aggiornamenti di stato
  • Aggiungi monitoraggio per rilevare e avvisare su eventi webhook mancati
  • Verifica che l’endpoint webhook sia accessibile e risponda correttamente
Sintomi: Il cliente effettua un downgrade ma non vede il saldo dei creditiCause comuni:
  • Aspettative sulla modalità di proration: i downgrade accreditano la differenza di prezzo totale del piano con difference_immediately, mentre prorated_immediately crea un credito prorato basato sul tempo rimanente nel ciclo
  • I crediti sono specifici per l’abbonamento e non si trasferiscono tra abbonamenti
  • Il saldo del credito non è visibile nel dashboard del cliente
Soluzioni:
  • Usa difference_immediately per i downgrade quando desideri crediti automatici
  • Spiega ai clienti che i crediti si applicano ai rinnovi futuri dello stesso abbonamento
  • Implementa un portale clienti per mostrare i saldi dei crediti
  • Controlla l’anteprima della prossima fattura per vedere i crediti applicati
Sintomi: Eventi webhook rifiutati a causa di firma non validaCause comuni:
  • Chiave segreta del webhook errata
  • Corpo della richiesta raw modificato prima della verifica della firma
  • Algoritmo di verifica della firma errato
Soluzioni:
  • Verifica di utilizzare la corretta DODO_WEBHOOK_SECRET dal dashboard
  • Leggi il corpo della richiesta raw prima di qualsiasi middleware di parsing JSON
  • Usa la libreria standard di verifica dei webhook per la tua piattaforma
  • Testa la verifica della firma del webhook nell’ambiente di sviluppo
Sintomi: L’API restituisce errore 422 Entità non elaborabileCause comuni:
  • ID abbonamento o ID prodotto non validi
  • Abbonamento non in stato attivo
  • Parametri richiesti mancanti
  • Prodotto non disponibile per cambiamenti di piano
Soluzioni:
  • Verifica che l’abbonamento esista e sia attivo
  • Controlla che l’ID prodotto sia valido e disponibile
  • Assicurati che tutti i parametri richiesti siano forniti
  • Rivedi la documentazione API per i requisiti dei parametri
Sintomi: Cambiamento di piano avviato ma l’addebito immediato fallisceCause comuni:
  • Fondi insufficienti sul metodo di pagamento del cliente
  • Metodo di pagamento scaduto o non valido
  • La banca ha rifiutato la transazione
  • La rilevazione delle frodi ha bloccato l’addebito
Soluzioni:
  • Gestisci gli eventi webhook payment.failed in modo appropriato
  • Notifica il cliente di aggiornare il metodo di pagamento
  • Implementa la logica di ripetizione per i fallimenti temporanei
  • Considera di consentire cambiamenti di piano con addebiti immediati falliti
Sintomi: L’addebito per il cambiamento di piano fallisce e l’abbonamento passa allo stato on_holdCosa succede: Quando un addebito per il cambiamento di piano fallisce, l’abbonamento viene automaticamente posto nello stato on_hold. L’abbonamento non si rinnoverà automaticamente fino a quando il metodo di pagamento non verrà aggiornato.Soluzione: Aggiorna il metodo di pagamento per riattivare l’abbonamentoPer riattivare un abbonamento dallo stato on_hold dopo un cambiamento di piano fallito:
  1. Aggiorna il metodo di pagamento utilizzando l’API Aggiorna Metodo di Pagamento
  2. Creazione automatica dell’addebito: L’API crea automaticamente un addebito per i restanti importi dovuti
  3. Generazione della fattura: Viene generata una fattura per l’addebito
  4. Elaborazione del pagamento: Il pagamento viene elaborato utilizzando il nuovo metodo di pagamento
  5. Riattivazione: Dopo un pagamento riuscito, l’abbonamento viene riattivato allo stato active
// Reactivate subscription from on_hold after failed plan change
async function reactivateAfterFailedPlanChange(subscriptionId) {
  // Update payment method - automatically creates charge for remaining dues
  const response = await client.subscriptions.updatePaymentMethod(subscriptionId, {
    type: 'new',
    return_url: 'https://example.com/return'
  });
  
  if (response.payment_id) {
    console.log('Charge created for remaining dues:', response.payment_id);
    console.log('Payment link:', response.payment_link);
    
    // Redirect customer to payment_link to complete payment
    // Monitor webhooks for:
    // 1. payment.succeeded - charge succeeded
    // 2. subscription.active - subscription reactivated
  }
  
  return response;
}

// Or use existing payment method if available
async function reactivateWithExistingPaymentMethod(subscriptionId, paymentMethodId) {
  const response = await client.subscriptions.updatePaymentMethod(subscriptionId, {
    type: 'existing',
    payment_method_id: paymentMethodId
  });
  
  // Monitor webhooks for payment.succeeded and subscription.active
  return response;
}
Eventi webhook da monitorare:
  • subscription.on_hold: Abbonamento messo in attesa (ricevuto quando l’addebito per il cambiamento di piano fallisce)
  • payment.succeeded: Pagamento per i restanti importi dovuti riuscito (dopo l’aggiornamento del metodo di pagamento)
  • subscription.active: Abbonamento riattivato dopo un pagamento riuscito
Migliori pratiche:
  • Notifica immediatamente i clienti quando un addebito per il cambiamento di piano fallisce
  • Fornisci istruzioni chiare su come aggiornare il loro metodo di pagamento
  • Monitora gli eventi webhook per tracciare lo stato di riattivazione
  • Considera di implementare una logica di ripetizione automatica per i fallimenti di pagamento temporanei

Riferimento API Aggiorna Metodo di Pagamento

Visualizza la documentazione API completa per aggiornare i metodi di pagamento e riattivare gli abbonamenti.

Testare la Tua Implementazione

Segui questi passaggi per testare a fondo la tua implementazione del cambiamento di piano di abbonamento:
1

Configura l'ambiente di test

  • Usa chiavi API di test e prodotti di test
  • Crea abbonamenti di test con diversi tipi di piano
  • Configura l’endpoint webhook di test
  • Imposta monitoraggio e registrazione
2

Testa diverse modalità di proration

  • Testa prorated_immediately con varie posizioni del ciclo di fatturazione
  • Testa difference_immediately per upgrade e downgrade
  • Testa full_immediately per resettare i cicli di fatturazione
  • Verifica che i calcoli dei crediti siano corretti
3

Testa la gestione dei webhook

  • Verifica che tutti gli eventi webhook pertinenti siano ricevuti
  • Testa la verifica della firma del webhook
  • Gestisci gli eventi webhook duplicati in modo elegante
  • Testa gli scenari di fallimento dell’elaborazione dei webhook
4

Testa gli scenari di errore

  • Testa con ID abbonamenti non validi
  • Testa con metodi di pagamento scaduti
  • Testa i fallimenti di rete e i timeout
  • Testa con fondi insufficienti
5

Monitora in produzione

  • Imposta avvisi per i cambiamenti di piano falliti
  • Monitora i tempi di elaborazione dei webhook
  • Traccia i tassi di successo dei cambiamenti di piano
  • Rivedi i ticket di supporto clienti per problemi di cambiamento di piano

Gestione degli Errori

Gestisci gli errori API comuni in modo elegante nella tua implementazione:

Codici di Stato HTTP

Richiesta di cambiamento di piano elaborata con successo. L’abbonamento viene aggiornato e l’elaborazione del pagamento è iniziata.
Parametri di richiesta non validi. Controlla che tutti i campi richiesti siano forniti e formattati correttamente.
Chiave API non valida o mancante. Verifica che la tua DODO_PAYMENTS_API_KEY sia corretta e abbia le autorizzazioni appropriate.
ID abbonamento non trovato o non appartiene al tuo account.
L’abbonamento non può essere cambiato (es. già annullato, prodotto non disponibile, ecc.).
Si è verificato un errore del server. Ripeti la richiesta dopo un breve ritardo.

Formato della Risposta di Errore

{
  "error": {
    "code": "subscription_not_found",
    "message": "The subscription with ID 'sub_123' was not found",
    "details": {
      "subscription_id": "sub_123"
    }
  }
}

Prossimi Passi