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 capability (Settings → Subscriptions → Collect Plan Change Payments by Payment Link), effective_at: immediately और on_payment_failure: prevent_change आवश्यक हैं। Collecting Payment via a Checkout Link देखें।Preview route द्वारा इसे अनदेखा किया जाता है।- प्रदान नहीं किया गया /
null—preserve_on_plan_change=trueवाले existing discounts को नए product पर लागू होने पर सुरक्षित रखा जाता है। [](empty array) — subscription से सभी existing discounts हटा देता है।["CODE_A", "CODE_B", ...]— किसी भी existing discounts को इस stacked set से replace करता है।
discount_codes को प्राथमिकता दें। यह field backward compatibility के लिए अभी भी काम करता है, लेकिन उसी request में इसे discount_codes के साथ combine नहीं किया जा सकता।immediately(default): Plan change तुरंत लागू करेंnext_billing_date: Change को अगली billing date के लिए schedule करें। Billing period समाप्त होने तक customer अपना current plan रखता है।
next_billing_date का उपयोग करें, ताकि billing period के अंत तक customers को अपने current plan के benefits मिलते रहें।Handle Webhook Events
subscription.active: Plan change सफल, subscription updatedsubscription.plan_changed: Subscription plan बदला गया (upgrade/downgrade/addon update)subscription.on_hold: Plan change charge विफल, renewals रोके गएpayment.succeeded: Plan change के लिए immediate charge सफलpayment.failed: Immediate charge विफल
Update Your Application State
- नए plan के आधार पर features grant/revoke करें
- नए plan के विवरण के साथ customer dashboard update करें
- Plan changes के बारे में confirmation emails भेजें
- Audit purposes के लिए billing changes log करें
Test and Monitor
- अलग-अलग scenarios के साथ सभी proration modes का परीक्षण करें
- Verify करें कि webhook handling सही ढंग से काम करती है
- Plan change success rates monitor करें
- Failed plan changes के लिए alerts सेट अप करें
Plan Changes का Preview
Plan change commit करने से पहले, customers को ठीक-ठीक यह दिखाने के लिए Preview API का उपयोग करें कि उनसे कितना charge लिया जाएगा:- Node.js SDK
- Python SDK
Change Plan API
Active subscription के product, quantity और proration behavior को modify करने के लिए Change Plan API का उपयोग करें।Quick start examples
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
200 OK लौटाता है — इससे पहले कि कोई charge वास्तव में settle हुआ हो। Body (ChangePlanResponse) में क्या शामिल है, यह इस बात पर निर्भर करता है कि change कैसे collect किया गया था:
collect_via_payment_link request के लिए यह बाद में और asynchronously resolve होता है — response आपको केवल checkout link देता है, subscription अपने current plan पर रहती है, और outcome के बारे में तब तक कुछ पता नहीं चलता जब तक customer उस link पर payment पूरा नहीं करता।किसी भी स्थिति में, इस response से outcome का अनुमान न लगाएँ। इसकी पुष्टि webhook (payment.succeeded, payment.failed, subscription.plan_changed) के माध्यम से करें या GET /subscriptions/{subscription_id} से subscription को दोबारा पढ़ें — payment-link case के लिए विशेष रूप से What Happens While the Link Is Unpaid देखें।Checkout Link के माध्यम से Payment Collect करना
Default रूप से, immediate plan change subscription के saved payment method से सीधे charge करता है। Customer को इसके बजाय hosted checkout page पर भेजने के लिएcollect_via_payment_link: true सेट करें — यह तब उपयोगी है जब ऐसा कोई saved payment method न हो जिसे आप off-session charge कर सकें, या जब आप customer से नई price को सक्रिय रूप से confirm करवाना चाहते हों।
Requirements
collect_via_payment_link: true केवल तब सफल होता है जब निम्न सभी शर्तें पूरी हों — अन्यथा request 422 के साथ विफल होती है:
- Business में
allow_plan_change_via_payment_linkcapability enabled हो (Settings → Subscriptions → Collect Plan Change Payments by Payment Link)। effective_at,immediatelyहो (default)। Scheduled change (next_billing_date) को checkout page की आवश्यकता कभी नहीं होती, क्योंकि charge उसके लागू होने तक नहीं किया जाता।- Effective
on_payment_failure,prevent_changeपर resolve हो। इसे explicitly भेजना आवश्यक नहीं है — यदि आपका business-level default (नीचे Business & Collection Defaults देखें) पहले सेprevent_changeहै, तो field को छोड़ना भी पर्याप्त है। Explicitapply_changeयाapply_changeका resolved default,422के साथ विफल होता है।
collect_via_payment_link केवल upgrades तक सीमित नहीं है — यह downgrades सहित किसी भी ऐसे immediate change पर लागू होता है जिससे charge बनता है, बशर्ते ऊपर दी गई requirements पूरी हों।proration_billing_mode: do_not_bill या कोई अन्य mode जो इस cycle में शून्य net करे — तो checkout page पर रखने के लिए कुछ नहीं है। कोई payment link जारी नहीं किया जाता, payment_link और अन्य fields null के रूप में लौटते हैं, और change तुरंत लागू हो जाता है, ठीक वैसे ही जैसे collect_via_payment_link के बिना होता। यह 422 नहीं है; flag केवल तब प्रभावी होता है जब collect करने के लिए positive amount हो। यदि आप स्पष्ट upgrades के बजाय सामान्य रूप से plan changes पर collect_via_payment_link सेट करते हैं, तो पहले Preview Plan Change call करें और केवल तभी link request करें जब preview की गई राशि collect करने योग्य हो।
- Node.js SDK
- Python SDK
- HTTP
Link Unpaid रहने पर क्या होता है
- Subscription अपने current plan पर रहती है —
product_id,recurring_pre_tax_amountऔरnext_billing_dateतब तक अपरिवर्तित रहते हैं जब तक link का भुगतान नहीं हो जाता। - Link pending रहने के दौरान उसी subscription पर किया गया अगला
change-planrequest409 PendingPlanChangeExistsके साथ reject हो जाता है। आवश्यकता होने पर scheduled change कोDELETE /subscriptions/{subscription_id}/change-plan/scheduledसे cancel करें, लेकिन वह endpoint pending payment-link change को cancel नहीं करता — केवल successful payment या expiry ऐसा करता है। - Decline के बाद customer उसी checkout session पर card retry कर सकता है; नया
change-plancall retry का तरीका नहीं है। - यदि link का कभी भुगतान नहीं होता, तो
expires_onके बाद वह काम करना बंद कर देता है — subscription थोड़े समय बाद नया plan-change request स्वीकार करने के लिए स्वतः उपलब्ध हो जाती है। - यदि कोई scheduled change (
next_billing_date) पहले से मौजूद था और आप उसेcancel_scheduled_change_plan: trueसे replace करते हैं, तो link unpaid रहने तक original schedule बना रहता है और link का भुगतान होने पर ही cancel होता है — उसी transaction में जिसमें नया plan लागू होता है।
Addons Manage करना
Subscription plans बदलते समय आप addons को भी modify कर सकते हैं:Discount Codes लागू करना
Subscription plans बदलते समय आप एक या अधिक stacked discount codes लागू कर सकते हैं (अधिकतम 20, array order में लागू)। यह upgrades या migrations पर promotional pricing देने के लिए उपयोगी है।- Node.js SDK
- Python SDK
- HTTP
Plan change पर discount behavior
discount_code field deprecated है, लेकिन backward compatibility के लिए अभी भी काम करता है — existing integrations को तुरंत बदलने की आवश्यकता नहीं है। इसे उसी request में discount_codes के साथ combine नहीं किया जा सकता। सुविधा के अनुसार array form पर migrate करें।Proration modes
Plans बदलते समय customer को bill करने का तरीका चुनें:prorated_immediately
- Current cycle में partial difference का charge करता है
- Trial में होने पर तुरंत charge करता है और अभी नए plan पर switch करता है
- Downgrade: future renewals पर लागू होने वाला prorated credit बना सकता है
full_immediately
- नए plan की पूरी राशि तुरंत charge करता है
- पुराने plan का बचा हुआ समय अनदेखा करता है
difference_immediately का उपयोग करके downgrades से बनाए गए credits subscription-scoped होते हैं और Credit-Based Billing entitlements से अलग होते हैं। वे उसी subscription के future renewals पर automatically लागू होते हैं और subscriptions के बीच transfer नहीं किए जा सकते।difference_immediately
- Upgrade: पुराने और नए plans के बीच price difference तुरंत charge करें
- Downgrade: बची हुई value को subscription में internal credit के रूप में जोड़ें और renewals पर automatically लागू करें
do_not_bill
- कोई charges या credits calculate नहीं किए जाते
- Customer बिना किसी billing adjustment के तुरंत नए plan पर switch करता है
- Billing cycle अपरिवर्तित रहता है
- Courtesy migrations, free plan switches या cost differences absorb करने के लिए सर्वोत्तम
Example scenarios
इन canonical numbers का लगातार उपयोग करें:- Current plan: Basic, $30/month
- Upgrade target: Pro, $80/month
- Downgrade target (Pro से): Starter, $20/month
- Billing cycle: 30 days, January 1 से शुरू
- Plan change January 16 को होता है (15 दिन शेष, 15 दिन उपयोग किए गए)
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
प्रत्येक mode billing को कैसे process करता है
Payment Failures को Handle करना
on_payment_failure parameter का उपयोग करके नियंत्रित करें कि plan change payment विफल होने पर क्या होता है।
Payment Failure Modes
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- Plan change को “pending” के रूप में mark किया जाता है
- Customer को अपने current plan का access मिलता रहता है
- Successful payment के बाद ही subscription
activestate में जाती है - Upgraded features देने से पहले payment सुनिश्चित करने के लिए उपयोगी
on_payment_failure parameter dashboard में configured business-level default setting का उपयोग करता है।प्रत्येक Mode का उपयोग कब करें
Business और Collection Defaults
हर plan change पर proration parameters pass करने के बजाय, business level पर default upgrade & downgrade behavior एक बार set कर सकते हैं। ये defaults सभी customer-portal plan changes पर लागू होते हैं और per product collection override किए जा सकते हैं। Upgrades और downgrades के लिए अलग-अलग defaults होते हैं:Resolution order
किसी भी plan change के लिए प्रत्येक setting इस order में resolve होती है:Webhooks Handle करना
Plan changes और payments की पुष्टि करने के लिए webhooks के माध्यम से subscription state track करें।Handle करने योग्य Event types
subscription.active: subscription activatedsubscription.plan_changed: subscription plan changed (upgrade/downgrade/addon changes)subscription.on_hold: charge failed, renewals stoppedsubscription.renewed: renewal succeededpayment.succeeded: plan change या renewal का payment succeededpayment.failed: payment failed
Signatures verify करें और intents handle करें
- Next.js Route Handler
- Express.js
Best Practices
Reliable subscription plan changes के लिए इन recommendations का पालन करें:Plan Change Strategy
- Thoroughly test करें: Production से पहले test mode में plan changes का हमेशा परीक्षण करें
- Proration सावधानी से चुनें: अपने business model के अनुरूप proration mode चुनें
- Failures को gracefully handle करें: उचित error handling और retry logic लागू करें
- Success rates monitor करें: Plan change success/failure rates track करें और issues की जांच करें
Webhook Implementation
- Signatures verify करें: Authenticity सुनिश्चित करने के लिए webhook signatures को हमेशा validate करें
- Idempotency लागू करें: Duplicate webhook events को gracefully handle करें
- Asynchronously process करें: Heavy operations से webhook responses को block न करें
- सब कुछ log करें: Debugging और audit purposes के लिए detailed logs रखें
User Experience
- स्पष्ट रूप से communicate करें: Customers को billing changes और timing के बारे में बताएं
- Confirmations प्रदान करें: सफल plan changes के लिए email confirmations भेजें
- Edge cases handle करें: Trial periods, prorations और failed payments पर विचार करें
- UI तुरंत update करें: अपने application interface में plan changes दिखाएं
Common Issues और Solutions
Subscription plan changes के दौरान आने वाली सामान्य समस्याओं का समाधान करें:Charge created but subscription not updated
Charge created but subscription not updated
- Webhook processing विफल या delayed था
- Webhooks प्राप्त होने के बाद application state update नहीं हुआ
- State update के दौरान database transaction issues
- Retry logic के साथ robust webhook handling लागू करें
- State updates के लिए idempotent operations का उपयोग करें
- Missed webhook events detect और alert करने के लिए monitoring जोड़ें
- Verify करें कि webhook endpoint accessible है और सही ढंग से respond कर रहा है
Credits not applied after downgrade
Credits not applied after downgrade
- Proration mode की अपेक्षाएं:
difference_immediatelyके साथ downgrades full plan price difference को credit करते हैं, जबकिprorated_immediatelycycle में बचे समय के आधार पर prorated credit बनाता है - Credits subscription-specific होते हैं और subscriptions के बीच transfer नहीं होते
- Customer dashboard में credit balance दिखाई नहीं देता
- Automatic credits चाहने पर downgrades के लिए
difference_immediatelyका उपयोग करें - Customers को समझाएं कि credits उसी subscription के future renewals पर लागू होते हैं
- Credit balances दिखाने के लिए customer portal लागू करें
- Applied credits देखने के लिए next invoice preview check करें
Webhook signature verification fails
Webhook signature verification fails
- Incorrect webhook secret key
- Signature verification से पहले raw request body modify की गई
- गलत signature verification algorithm
- Verify करें कि dashboard से सही
DODO_WEBHOOK_SECRETउपयोग कर रहे हैं - किसी भी JSON parsing middleware से पहले raw request body पढ़ें
- अपने platform के लिए standard webhook verification library का उपयोग करें
- Development environment में webhook signature verification का परीक्षण करें
Plan change fails with 422 error
Plan change fails with 422 error
- Invalid subscription ID या product ID
- Subscription active state में नहीं है
- Required parameters missing हैं
- Product plan changes के लिए उपलब्ध नहीं है
- Verify करें कि subscription मौजूद और active है
- Check करें कि product ID valid और available है
- सुनिश्चित करें कि सभी required parameters दिए गए हैं
- Parameter requirements के लिए API documentation देखें
Immediate charge fails during plan change
Immediate charge fails during plan change
- Customer के payment method में insufficient funds
- Payment method expired या invalid है
- Bank ने transaction decline कर दिया
- Fraud detection ने charge block कर दिया
payment.failedwebhook events को उचित ढंग से handle करें- Customer को payment method update करने के लिए notify करें
- Temporary failures के लिए retry logic लागू करें
- Failed immediate charges के साथ plan changes allow करने पर विचार करें
Subscription on hold after plan change
Subscription on hold after plan change
on_hold state में चली जाती हैWhat happens:
जब plan change charge विफल होता है, तो subscription automatically on_hold state में चली जाती है। Payment method update होने तक subscription automatically renew नहीं होगी।Solution: Subscription को reactivate करने के लिए payment method update करेंFailed plan change के बाद subscription को on_hold state से reactivate करने के लिए:- Payment method update करें: Update Payment Method API का उपयोग करें
- Automatic charge creation: API remaining dues के लिए automatically charge बनाती है
- Invoice generation: Charge के लिए invoice generate की जाती है
- Payment processing: नए payment method का उपयोग करके payment process किया जाता है
- Reactivation: Successful payment के बाद subscription
activestate में reactivate हो जाती है
subscription.on_hold: Subscription hold पर रखी गई (plan change charge विफल होने पर प्राप्त)payment.succeeded: Remaining dues का payment सफल (payment method update करने के बाद)subscription.active: Successful payment के बाद subscription reactivated
- Plan change charge विफल होने पर customers को तुरंत notify करें
- Payment method update करने का स्पष्ट तरीका बताएं
- Reactivation status track करने के लिए webhook events monitor करें
- Temporary payment failures के लिए automatic retry logic लागू करने पर विचार करें
Update Payment Method API Reference
अपने Implementation का परीक्षण
अपने subscription plan change implementation का पूरी तरह परीक्षण करने के लिए इन steps का पालन करें:Set up test environment
- Test API keys और test products का उपयोग करें
- अलग-अलग plan types वाली test subscriptions बनाएं
- Test webhook endpoint configure करें
- Monitoring और logging सेट अप करें
Test different proration modes
- विभिन्न billing cycle positions के साथ
prorated_immediatelyका परीक्षण करें - Upgrades और downgrades के लिए
difference_immediatelyका परीक्षण करें - Billing cycles reset करने के लिए
full_immediatelyका परीक्षण करें - No-charge/no-credit plan switches के लिए
do_not_billका परीक्षण करें - Verify करें कि credit calculations सही हैं
Test webhook handling
- Verify करें कि सभी relevant webhook events प्राप्त हो रहे हैं
- Webhook signature verification का परीक्षण करें
- Duplicate webhook events को gracefully handle करें
- Webhook processing failure scenarios का परीक्षण करें
Test error scenarios
- Invalid subscription IDs के साथ परीक्षण करें
- Expired payment methods के साथ परीक्षण करें
- Network failures और timeouts का परीक्षण करें
- Insufficient funds के साथ परीक्षण करें
Monitor in production
- Failed plan changes के लिए alerts सेट अप करें
- Webhook processing times monitor करें
- Plan change success rates track करें
- Plan change issues के लिए customer support tickets review करें
Error Handling
अपने implementation में common API errors को gracefully handle करें:HTTP Status Codes
200 OK
200 OK
collect_via_payment_link request को छोड़कर response body empty होती है; ऐसी request checkout handles लौटाती है — Collecting Payment via a Checkout Link देखें। यदि on_payment_failure=prevent_change है, तो payment सफल होने तक plan change pending रहती है।400 Bad Request
400 Bad Request
404 Not Found
404 Not Found
409 Conflict
409 Conflict
PendingPlanChangeExists)। Scheduled change के लिए नया change submit करने से पहले इसे DELETE /subscriptions/{subscription_id}/change-plan/scheduled से cancel करें। Pending payment-link change के लिए कोई cancel endpoint नहीं है — customer के payment करने या link expire होने के बाद subscription नया plan-change request स्वीकार करती है।422 Unprocessable Entity
422 Unprocessable Entity
collect_via_payment_link के लिए eligible नहीं है — business में capability enabled नहीं है, effective_at immediately नहीं है, या on_payment_failure prevent_change नहीं है। Requirements देखें।500 Internal Server Error
500 Internal Server Error
Error Response Format
Next steps
- Change Plan API review करें
- Credit-Based Billing explore करें
subscription.on_holdके लिए alerts लागू करें- हमारी Webhook Integration Guide देखें