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 de l’entreprise (Settings → Subscriptions → Collect Plan Change Payments by Payment Link), effective_at: immediately et on_payment_failure: prevent_change. Consultez Collecting Payment via a Checkout Link.Ignoré par la route de preview.- Non fourni /
null— les réductions existantes avecpreserve_on_plan_change=truesont conservées si elles s’appliquent au nouveau produit. [](tableau vide) — supprime toutes les réductions existantes de l’abonnement.["CODE_A", "CODE_B", ...]— remplace toutes les réductions existantes par cet ensemble empilé.
discount_codes pour les nouvelles intégrations. Ce champ fonctionne toujours pour assurer la rétrocompatibilité, mais ne peut pas être combiné avec discount_codes dans la même requête.immediately(par défaut) : applique le changement de plan immédiatementnext_billing_date: planifie le changement pour la prochaine date de facturation. Le client conserve son plan actuel jusqu’à la fin de la période de facturation.
next_billing_date pour les downgrades afin que les clients conservent les avantages de leur plan actuel jusqu’à la fin de la période de facturation.Handle Webhook Events
subscription.active: changement de plan réussi, abonnement mis à joursubscription.plan_changed: plan d’abonnement modifié (upgrade/downgrade/mise à jour d’addon)subscription.on_hold: échec du débit du changement de plan, renouvellements arrêtéspayment.succeeded: débit immédiat du changement de plan réussipayment.failed: échec du débit immédiat
Update Your Application State
- Accordez ou révoquez les fonctionnalités selon le nouveau plan
- Mettez à jour le tableau de bord client avec les détails du nouveau plan
- Envoyez des e-mails de confirmation concernant les changements de plan
- Consignez les changements de facturation à des fins d’audit
Test and Monitor
- Testez tous les modes de proratisation avec différents scénarios
- Vérifiez que la gestion des webhooks fonctionne correctement
- Surveillez les taux de réussite des changements de plan
- Configurez des alertes pour les changements de plan échoués
Prévisualiser les changements de plan
Avant de valider un changement de plan, utilisez l’API Preview pour montrer aux clients exactement le montant qui leur sera facturé :- Node.js SDK
- Python SDK
API Change Plan
Utilisez l’API Change Plan pour modifier le produit, la quantité et le comportement de la proratisation d’un abonnement actif.Exemples de démarrage rapide
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
200 OK — avant que le moindre débit ne soit effectivement réglé. Le contenu du corps (ChangePlanResponse) dépend de la manière dont le changement a été collecté :
collect_via_payment_link, le résultat est déterminé ultérieurement et de manière asynchrone : la réponse vous remet uniquement un lien de checkout, l’abonnement reste sur son plan actuel et le résultat reste inconnu jusqu’à ce que le client effectue effectivement le paiement via ce lien.Dans tous les cas, ne déduisez pas le résultat de cette réponse. Confirmez-le via un webhook (payment.succeeded, payment.failed, subscription.plan_changed) ou en relisant l’abonnement avec GET /subscriptions/{subscription_id} — consultez What Happens While the Link Is Unpaid pour le cas du lien de paiement.Collecter un paiement via un lien de checkout
Par défaut, un changement de plan immédiat débite directement le moyen de paiement enregistré de l’abonnement. Définissezcollect_via_payment_link: true pour rediriger le client vers une page de checkout hébergée — cette option est utile lorsqu’aucun moyen de paiement enregistré ne peut être débité hors session, ou lorsque vous souhaitez que le client confirme activement le nouveau prix.
Conditions requises
collect_via_payment_link: true ne réussit que lorsque toutes les conditions suivantes sont remplies — sinon la requête échoue avec 422 :
- L’entreprise a activé la capacité
allow_plan_change_via_payment_link(Settings → Subscriptions → Collect Plan Change Payments by Payment Link). effective_atest égal àimmediately(la valeur par défaut). Un changement planifié (next_billing_date) n’a jamais besoin d’une page de checkout, car aucun montant n’est facturé avant son application.- La valeur effective de
on_payment_failurese résout enprevent_change. Vous n’avez pas besoin de l’envoyer explicitement : si la valeur par défaut au niveau de l’entreprise (voir Business & Collection Defaults ci-dessous) est déjàprevent_change, l’omission du champ suffit également. Une valeur expliciteapply_change, ou une valeur par défaut résolue enapply_change, échoue avec422.
collect_via_payment_link ne se limite pas aux upgrades : il s’applique à tout changement immédiat entraînant un débit, y compris les downgrades, tant que les conditions ci-dessus sont remplies.proration_billing_mode: do_not_bill, ou un autre mode dont le solde net est nul pour ce cycle — il n’y a rien à placer sur une page de checkout. Aucun lien de paiement n’est émis, payment_link et les champs associés renvoient null, et le changement s’applique immédiatement, comme il le ferait sans collect_via_payment_link. Il ne s’agit pas d’une 422 ; cet indicateur ne prend effet que lorsqu’un montant positif doit être collecté. Si vous définissez collect_via_payment_link pour les changements de plan de manière générale plutôt que pour des upgrades clairement identifiés, appelez d’abord Preview Plan Change et ne demandez un lien que lorsque le montant prévisualisé mérite d’être collecté.
- Node.js SDK
- Python SDK
- HTTP
Ce qui se passe tant que le lien n’est pas payé
- L’abonnement reste sur son plan actuel —
product_id,recurring_pre_tax_amountetnext_billing_daterestent tous inchangés jusqu’au paiement du lien. - Toute nouvelle requête
change-plansur le même abonnement est rejetée avec409 PendingPlanChangeExiststant que le lien est en attente. Annulez un changement planifié avecDELETE /subscriptions/{subscription_id}/change-plan/scheduledsi nécessaire, mais cet endpoint n’annule pas un changement par lien de paiement en attente : seul un paiement réussi ou l’expiration du lien le permet. - Après un refus, le client peut réessayer avec une carte dans la même session de checkout ; un nouvel appel
change-plann’est pas la procédure de nouvelle tentative. - Si le lien n’est jamais payé, il cesse de fonctionner après
expires_on— l’abonnement redevient automatiquement disponible pour accepter une nouvelle requête de changement de plan peu après. - Si un changement planifié (
next_billing_date) existait déjà et que vous le remplacez parcancel_scheduled_change_plan: true, la planification d’origine reste en place tant que le lien n’est pas payé et n’est annulée qu’une fois le lien payé — dans la même transaction que celle qui applique le nouveau plan.
Gérer les addons
Lors de la modification des plans d’abonnement, vous pouvez également modifier les addons :Appliquer des codes de réduction
Vous pouvez appliquer un ou plusieurs codes de réduction empilés lors de la modification des plans d’abonnement (20 maximum, appliqués dans l’ordre du tableau). Cette fonctionnalité est utile pour proposer des tarifs promotionnels lors d’upgrades ou de migrations.- Node.js SDK
- Python SDK
- HTTP
Comportement des réductions lors d’un changement de plan
discount_code de cet endpoint est obsolète, mais fonctionne toujours pour assurer la rétrocompatibilité — les intégrations existantes n’ont pas besoin d’être modifiées immédiatement. Il ne peut pas être combiné avec discount_codes dans la même requête. Migrez vers la forme tableau lorsque cela vous conviendra.Modes de proratisation
Choisissez comment facturer le client lors d’un changement de plan :prorated_immediately
- Facture la différence partielle pour le cycle actuel
- En période d’essai, facture immédiatement et bascule maintenant vers le nouveau plan
- Downgrade : peut générer un crédit proratisé appliqué aux futurs renouvellements
full_immediately
- Facture immédiatement le montant total du nouveau plan
- Ignore le temps restant de l’ancien plan
difference_immediately sont associés à l’abonnement et distincts des avantages de Credit-Based Billing. Ils s’appliquent automatiquement aux futurs renouvellements du même abonnement et ne sont pas transférables entre abonnements.difference_immediately
- Upgrade : facture immédiatement la différence de prix entre l’ancien et le nouveau plan
- Downgrade : ajoute la valeur restante sous forme de crédit interne à l’abonnement et l’applique automatiquement aux renouvellements
do_not_bill
- Aucun débit ni crédit n’est calculé
- Le client passe immédiatement au nouveau plan sans ajustement de facturation
- Le cycle de facturation reste inchangé
- Idéal pour les migrations commerciales, les passages à un plan gratuit ou l’absorption des différences de coût
Exemples de scénarios
Utilisez systématiquement ces valeurs de référence :- Plan actuel : Basic à 30 $/mois
- Cible de l’upgrade : Pro à 80 $/mois
- Cible du downgrade (depuis Pro) : Starter à 20 $/mois
- Cycle de facturation : 30 jours, commencé le 1er janvier
- Le changement de plan a lieu le 16 janvier (15 jours restants, 15 jours écoulés)
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
Traitement de la facturation selon chaque mode
Gérer les échecs de paiement
Contrôlez ce qui se passe lorsqu’un paiement de changement de plan échoue à l’aide du paramètreon_payment_failure.
Modes d’échec de paiement
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- Le changement de plan est marqué comme « en attente »
- Le client conserve l’accès à son plan actuel
- L’abonnement ne passe à l’état
activequ’après la réussite du paiement - Utile lorsque vous souhaitez vous assurer du paiement avant d’accorder les fonctionnalités améliorées
on_payment_failure utilise la valeur par défaut au niveau de l’entreprise, configurée dans le tableau de bord.Quand utiliser chaque mode
Valeurs par défaut de l’entreprise et de la collection
Au lieu de transmettre des paramètres de proratisation à chaque changement de plan, vous pouvez définir une fois le comportement par défaut des upgrades et downgrades au niveau de l’entreprise. Ces valeurs par défaut s’appliquent à tous les changements de plan du portail client et peuvent être remplacées pour chaque collection de produits. Des valeurs par défaut distinctes sont disponibles pour les upgrades et les downgrades :Ordre de résolution
Pour un changement de plan donné, chaque paramètre est résolu dans l’ordre suivant :Gérer les webhooks
Suivez l’état de l’abonnement via les webhooks pour confirmer les changements de plan et les paiements.Types d’événements à gérer
subscription.active: abonnement activésubscription.plan_changed: plan d’abonnement modifié (upgrade/downgrade/modifications d’addons)subscription.on_hold: débit échoué, renouvellements arrêtéssubscription.renewed: renouvellement réussipayment.succeeded: paiement du changement de plan ou du renouvellement réussipayment.failed: paiement échoué
Vérifier les signatures et gérer les intents
- Next.js Route Handler
- Express.js
Bonnes pratiques
Suivez ces recommandations pour garantir la fiabilité des changements de plan d’abonnement :Stratégie de changement de plan
- Testez soigneusement : testez toujours les changements de plan en mode test avant la production
- Choisissez la proratisation avec attention : sélectionnez le mode de proratisation adapté à votre modèle économique
- Gérez les échecs avec élégance : implémentez une gestion appropriée des erreurs et une logique de nouvelle tentative
- Surveillez les taux de réussite : suivez les taux de réussite et d’échec des changements de plan et examinez les problèmes
Implémentation des webhooks
- Vérifiez les signatures : validez toujours les signatures des webhooks pour garantir leur authenticité
- Implémentez l’idempotence : gérez correctement les événements webhook en double
- Traitez les événements de manière asynchrone : ne bloquez pas les réponses webhook avec des opérations lourdes
- Consignez tout : conservez des journaux détaillés à des fins de débogage et d’audit
Expérience utilisateur
- Communiquez clairement : informez les clients des changements de facturation et de leur calendrier
- Fournissez des confirmations : envoyez des confirmations par e-mail pour les changements de plan réussis
- Gérez les cas particuliers : tenez compte des périodes d’essai, des proratisations et des paiements échoués
- Mettez l’interface à jour immédiatement : reflétez les changements de plan dans l’interface de votre application
Problèmes courants et solutions
Résolvez les problèmes typiques rencontrés lors des changements de plan d’abonnement :Charge created but subscription not updated
Charge created but subscription not updated
- Le traitement du webhook a échoué ou a été retardé
- L’état de l’application n’a pas été mis à jour après la réception des webhooks
- Problèmes de transaction de base de données lors de la mise à jour de l’état
- Implémentez une gestion robuste des webhooks avec une logique de nouvelle tentative
- Utilisez des opérations idempotentes pour les mises à jour d’état
- Ajoutez une surveillance pour détecter les événements webhook manqués et déclencher des alertes
- Vérifiez que l’endpoint webhook est accessible et répond correctement
Credits not applied after downgrade
Credits not applied after downgrade
- Attentes liées au mode de proratisation : les downgrades créditent la différence totale de prix entre les plans avec
difference_immediately, tandis queprorated_immediatelycrée un crédit proratisé fondé sur le temps restant du cycle - Les crédits sont spécifiques à l’abonnement et ne sont pas transférables entre abonnements
- Le solde de crédits n’est pas visible dans le tableau de bord client
- Utilisez
difference_immediatelypour les downgrades lorsque vous souhaitez des crédits automatiques - Expliquez aux clients que les crédits s’appliquent aux futurs renouvellements du même abonnement
- Implémentez le portail client pour afficher les soldes de crédits
- Consultez la preview de la prochaine facture pour voir les crédits appliqués
Webhook signature verification fails
Webhook signature verification fails
- Clé secrète webhook incorrecte
- Corps brut de la requête modifié avant la vérification de la signature
- Algorithme de vérification de signature incorrect
- Vérifiez que vous utilisez le bon
DODO_WEBHOOK_SECRETdepuis le tableau de bord - Lisez le corps brut de la requête avant tout middleware d’analyse JSON
- Utilisez la bibliothèque standard de vérification des webhooks pour votre plateforme
- Testez la vérification des signatures webhook dans l’environnement de développement
Plan change fails with 422 error
Plan change fails with 422 error
- ID d’abonnement ou ID de produit invalide
- Abonnement dans un état inactif
- Paramètres requis manquants
- Produit non disponible pour les changements de plan
- Vérifiez que l’abonnement existe et est actif
- Vérifiez que l’ID du produit est valide et disponible
- Assurez-vous que tous les paramètres requis sont fournis
- Consultez la documentation de l’API pour connaître les exigences des paramètres
Immediate charge fails during plan change
Immediate charge fails during plan change
- Fonds insuffisants sur le moyen de paiement du client
- Moyen de paiement expiré ou invalide
- Transaction refusée par la banque
- Débit bloqué par la détection des fraudes
- Gérez correctement les événements webhook
payment.failed - Demandez au client de mettre à jour son moyen de paiement
- Implémentez une logique de nouvelle tentative pour les échecs temporaires
- Envisagez d’autoriser les changements de plan malgré les échecs de débits immédiats
Subscription on hold after plan change
Subscription on hold after plan change
on_holdCe qui se passe :
Lorsqu’un débit de changement de plan échoue, l’abonnement est automatiquement placé à l’état on_hold. Il ne se renouvellera pas automatiquement tant que le moyen de paiement n’aura pas été mis à jour.Solution : mettez à jour le moyen de paiement pour réactiver l’abonnementPour réactiver un abonnement à l’état on_hold après un changement de plan échoué :- Mettez à jour le moyen de paiement à l’aide de l’API Update Payment Method
- Création automatique du débit : l’API crée automatiquement un débit pour les sommes restantes dues
- Génération de la facture : une facture est générée pour le débit
- Traitement du paiement : le paiement est traité avec le nouveau moyen de paiement
- Réactivation : après la réussite du paiement, l’abonnement est réactivé à l’état
active
subscription.on_hold: abonnement mis en attente (reçu lorsque le débit du changement de plan échoue)payment.succeeded: paiement des sommes restantes dues réussi (après la mise à jour du moyen de paiement)subscription.active: abonnement réactivé après la réussite du paiement
- Informez immédiatement les clients lorsqu’un débit de changement de plan échoue
- Fournissez des instructions claires pour mettre à jour leur moyen de paiement
- Surveillez les événements webhook pour suivre l’état de la réactivation
- Envisagez d’implémenter une logique de nouvelle tentative automatique pour les échecs de paiement temporaires
Update Payment Method API Reference
Tester votre implémentation
Suivez ces étapes pour tester soigneusement votre implémentation des changements de plan d’abonnement :Set up test environment
- Utilisez des clés API de test et des produits de test
- Créez des abonnements de test avec différents types de plans
- Configurez un endpoint webhook de test
- Configurez la surveillance et la journalisation
Test different proration modes
- Testez
prorated_immediatelyavec différentes positions dans le cycle de facturation - Testez
difference_immediatelypour les upgrades et les downgrades - Testez
full_immediatelypour réinitialiser les cycles de facturation - Testez
do_not_billpour les changements de plan sans débit ni crédit - Vérifiez que les calculs de crédits sont corrects
Test webhook handling
- Vérifiez que tous les événements webhook pertinents sont reçus
- Testez la vérification des signatures webhook
- Gérez correctement les événements webhook en double
- Testez les scénarios d’échec du traitement des webhooks
Test error scenarios
- Testez avec des ID d’abonnement invalides
- Testez avec des moyens de paiement expirés
- Testez les défaillances réseau et les expirations de délai
- Testez avec des fonds insuffisants
Monitor in production
- Configurez des alertes pour les changements de plan échoués
- Surveillez les délais de traitement des webhooks
- Suivez les taux de réussite des changements de plan
- Examinez les tickets du support client relatifs aux problèmes de changement de plan
Gestion des erreurs
Gérez correctement les erreurs API courantes dans votre implémentation :Codes d’état HTTP
200 OK
200 OK
collect_via_payment_link réussie, qui renvoie des identifiants de checkout — consultez Collecting Payment via a Checkout Link. Si on_payment_failure=prevent_change, le changement de plan reste en attente jusqu’à la réussite du paiement.400 Bad Request
400 Bad Request
404 Not Found
404 Not Found
409 Conflict
409 Conflict
PendingPlanChangeExists). Pour un changement planifié, annulez-le avec DELETE /subscriptions/{subscription_id}/change-plan/scheduled avant d’en soumettre un nouveau. Pour un changement par lien de paiement en attente, aucun endpoint d’annulation n’existe : l’abonnement accepte une nouvelle requête de changement de plan une fois que le client paie ou que le lien expire.422 Unprocessable Entity
422 Unprocessable Entity
collect_via_payment_link — l’entreprise n’a pas activé la capacité, effective_at n’est pas égal à immediately, ou on_payment_failure n’est pas égal à prevent_change. Consultez Conditions requises.500 Internal Server Error
500 Internal Server Error
Format de réponse d’erreur
Étapes suivantes
- Consultez l’API Change Plan
- Découvrez la Credit-Based Billing
- Implémentez des alertes pour
subscription.on_hold - Consultez notre guide d’intégration des webhooks