Change Plan API
Plan Change Preview
Integration Guide
サブスクリプションのアップグレードまたはダウングレードとは?
顧客のサブスクリプションプランを変更して、異なるティア間で移動させたり、seat-based products の数量を調整したり、新しい product に移行したりできます。API は、選択した billing mode に基づいて日割り計算と請求を自動的に行います。プラン変更を使用するタイミング
- 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
- 現在のサイクルの未使用部分を、残り時間に応じて日割りでクレジットします
- その後、新しいプランの full サイクルを請求します。新しいプランの料金が日割りになることはありません
- 正味の請求額 = 新しいサイクル全額 −(残りの割合 × 古いサイクル全額)
Implement the Change Plan API
prorated_immediately, full_immediately, difference_immediately, or do_not_bill.nullを送信する、または空の配列を送信すると、既存のアドオンがすべて削除されます。保持するには、現在のアドオンを含めてください。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を持つ既存のdiscountsは、新しいproductに適用可能であれば保持されます。 [](空のarray) — サブスクリプションから既存のdiscountsをすべて削除します。["CODE_A", "CODE_B", ...]— 既存のdiscountsを、このstacked setに置き換えます。
discount_codes を使用してください。このfieldは後方互換性のため引き続き動作しますが、同じrequestで discount_codes と組み合わせることはできません。immediately(デフォルト):プラン変更を直ちに適用next_billing_date:次回の請求日に変更を適用。請求期間が終了するまで、顧客は現在のプランを保持します。顧客が請求期間の終了まで現在のプランのbenefitsを利用できるようにするため、ダウングレードではこれを使用してください。
Handle Webhook Events
subscription.active:プラン変更成功、subscription updatedsubscription.plan_changed:サブスクリプションプラン変更(アップグレード/ダウングレード/addon update)subscription.on_hold:プラン変更の請求に失敗、更新を停止payment.succeeded:プラン変更の即時請求に成功payment.failed:即時請求に失敗
Update Your Application State
- 新しいプランに基づいてfeaturesを付与/取り消し
- 新しいプランのdetailsでcustomer dashboardを更新
- プラン変更の確認メールを送信
- audit purposesのためbilling changesを記録
Test and Monitor
- さまざまなシナリオですべてのproration modesをテスト
- webhook handlingが正しく動作することを確認
- プラン変更の成功率を監視
- 失敗したプラン変更のalertを設定
プラン変更のPreview
プラン変更を確定する前に、Preview APIを使用して、顧客に請求される正確な金額を表示します:- Node.js SDK
- Python SDK
Change Plan API
Change Plan APIを使用して、アクティブなサブスクリプションのproduct、quantity、proration behaviorを変更します。Quick Start Examples
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
200 OK が直ちに返されます。これは、実際に請求がsettledする前です。body(ChangePlanResponse)の内容は、変更の支払い方法によって異なります:
collect_via_payment_link requestでは、顧客が支払いを完了するまでサブスクリプションは現在のプランに留まります。webhook(payment.succeeded、payment.failed、subscription.plan_changed)で結果を確認するか、GET /subscriptions/{subscription_id} を使用してsubscriptionを再読み込みしてください。payment-linkの場合は、What Happens While the Link Is Unpaidを参照してください。Checkout Linkによる支払いの回収
デフォルトでは、即時のプラン変更によって、subscriptionのsaved payment methodに直接請求されます。顧客をhosted checkout pageへ送るにはcollect_via_payment_link: true を設定します。saved payment methodがない場合や、顧客に新しい価格を明示的に確認してもらいたい場合に便利です。
Requirements
collect_via_payment_link: true は、次の すべて を満たす場合にのみ成功します。それ以外の場合、requestは 422 で失敗します:
- businessで
allow_plan_change_via_payment_linkcapabilityが有効になっている(Settings → Subscriptions → Collect Plan Change Payments by Payment Link)。 effective_atがimmediately(デフォルト)であること。scheduled change(next_billing_date)にcheckout pageは必要ありません。- effective
on_payment_failureがprevent_changeに解決されること。明示的に送信する必要はありません。business-level defaultがすでにprevent_changeであれば、fieldを省略しても条件を満たします。明示的なapply_changeは422で失敗します。
collect_via_payment_link は、上記の要件を満たす限り、ダウングレードを含む、請求が発生するすべての即時変更に適用されます。payment_link とその他のcheckout fieldsは null として返され、変更は直ちに適用されます。これは 422 ではありません。linkをrequestする前に、Preview Plan Changeを呼び出して金額を確認してください。
- Node.js SDK
- Python SDK
- HTTP
Linkが未払いの間に発生すること
- subscriptionはcurrent planに留まります。
product_id、recurring_pre_tax_amount、next_billing_dateは、linkの支払いが完了するまで変更されません。 - linkがpendingの間は、追加の
change-planrequestは409 PendingPlanChangeExistsで拒否されます。必要であれば、DELETE /subscriptions/{subscription_id}/change-plan/scheduledでscheduled changeをキャンセルできます。ただし、このendpointはpending payment-link changeをキャンセルしません。キャンセルされるのは、支払いが成功した場合または期限切れになった場合のみです。 - 顧客は、decline後も同じcheckout sessionでカードを再試行できます。新しい
change-plancallを行うことはretry pathではありません。 - linkが支払われない場合、
expires_on後に機能しなくなります。その後まもなく、subscriptionは新しいplan-change requestを受け付けられる状態になります。 - scheduled changeがすでに存在し、それを
cancel_scheduled_change_plan: trueで置き換えた場合、linkが未払いの間は元のscheduleが維持されます。linkの支払いが完了した時点でのみ、new planを適用する同一transaction内でキャンセルされます。
Addonsの管理
サブスクリプションプランの変更時に、addonsも変更できます:Discount Codesの適用
サブスクリプションプランの変更時に、1つ以上のstacked discount codesを適用します(最大20個、arrayの順序で適用):- Node.js SDK
- Python SDK
- HTTP
プラン変更時のDiscount Behavior
discount_code fieldはdeprecatedですが、後方互換性のため引き続き動作します。既存のintegrationsはすぐに変更する必要はありません。同じrequestで discount_codes と組み合わせることはできません。都合のよいタイミングでarray形式へ移行してください。Proration Modes
プラン変更時に顧客へどのように請求するかを選択します:prorated_immediately
- 現在のサイクルの未使用部分(base plan、quantity、add-ons)を残り時間に応じて日割りでクレジット
- その後、新しいplan、quantity、add-onsのfull cycleを請求します。請求自体が日割りになることはありません
- 正味の即時請求額 =(新しいサイクル全額)−(残りの割合 × 古いサイクル全額)
- クレジットが新しいサイクルの請求額を超える場合(ダウングレードでよく発生)、差額はsubscription-scoped creditとして今後の更新に使用されます
- trial中の場合は、直ちに請求して新しいプランへ切り替えます
full_immediately
- 新しいプランの全額を直ちに請求
- 古いプランの残り時間を無視し、現在のサイクルに対するクレジットは付与しません
prorated_immediatelyによって作成されたクレジットと、difference_immediatelyを使用したダウングレードによって作成されたクレジットは、subscription-scopedであり、Credit-Based Billing entitlementsとは異なります。これらは同じsubscriptionの今後の更新に自動的に適用され、subscription間でtransferすることはできません。difference_immediately
- アップグレード:古いプランと新しいプランの価格差を直ちに請求
- ダウングレード:残りの価値をsubscriptionのinternal creditとして追加し、更新時に自動適用
do_not_bill
- 請求もクレジット計算も行いません
- 請求調整なしで、顧客を直ちに新しいプランへ切り替えます
- billing cycleは変更されません
- 好意による移行、無料プランへの切り替え、または料金差を事業者が負担する場合に最適
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処理
Payment Failuresの処理
on_payment_failure parameterを使用して、プラン変更の支払いに失敗した場合の動作を制御します。
Payment Failure Modes
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- プラン変更は「pending」としてマークされます
- 顧客は現在のプランへのaccessを保持します
- 支払いが成功した後にのみ、subscriptionは
activestateへ移行します - アップグレードfeaturesを付与する前に支払いを確実にしたい場合に便利です
on_payment_failure parameterはdashboardで設定されたbusiness-level default settingを使用します。各Modeを使用するタイミング
Business & Collection Defaults
Settings → Subscriptions でbusiness levelのアップグレードおよびダウングレードの動作を設定します。これらのdefaultsは、すべてのcustomer-portal plan changesに適用され、product collectionごとにoverrideできます。 アップグレードとダウングレードには、それぞれ別のdefaultsがあります:Resolution Order
特定のプラン変更では、各settingが次の順序で解決されます:Webhooksの処理
webhooksを通じてsubscription stateを追跡し、プラン変更と支払いを確認します。処理する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の検証とIntentsの処理
- Next.js Route Handler
- Express.js
Best Practices
Plan Change Strategy
- 十分にテストする:production前に必ずtest modeでプラン変更をテストする
- prorationを慎重に選択する:business modelに合ったproration modeを選択する
- failureを適切に処理する:適切なerror handlingとretry logicを実装する
- 成功率を監視する:プラン変更の成功率/失敗率を追跡し、問題を調査する
Webhook Implementation
- signaturesを検証する:authenticityを確保するため、必ずwebhook signaturesを検証する
- idempotencyを実装する:重複するwebhook eventsを適切に処理する
- 非同期で処理する:重い処理でwebhook responsesをブロックしない
- すべてを記録する:debuggingとaudit purposesのため、詳細なlogsを維持する
User Experience
- 明確に伝える:billing changesとタイミングを顧客に知らせる
- confirmationsを提供する:プラン変更成功時にconfirmation emailsを送信する
- edge casesを処理する:trial periods、prorations、failed paymentsを考慮する
- UIを直ちに更新する:アプリケーションinterfaceにプラン変更を反映する
よくある問題と解決策
サブスクリプションのプラン変更中に発生する一般的な問題を解決します:Charge created but subscription not updated
Charge created but subscription not updated
- Webhook processingが失敗または遅延した
- webhook受信後にapplication stateが更新されていない
- state update中のdatabase transaction issues
- retry logicを使用したwebhook handlingを実装する
- state updatesにidempotent operationsを使用する
- missed webhook eventsを検出してalertするmonitoringを追加する
- webhook endpointにaccessでき、正しく応答していることを確認する
Credits not applied after downgrade
Credits not applied after downgrade
- Proration modeの想定:ダウングレードでは
difference_immediatelyによりfull plan price differenceがクレジットされます。一方prorated_immediatelyでは、古いcycleの未使用期間がクレジットされ、その後新しいplanのfull cycleが請求されます。そのため、credit balanceが残るのはそのクレジットが新しいplan priceを超える場合のみです - Creditsはsubscription-specificであり、subscription間でtransferされない
- Credit balanceがcustomer dashboardに表示されない
- 自動creditsが必要なダウングレードには
difference_immediatelyを使用する - creditsは同じsubscriptionのfuture renewalsに適用されることを顧客に説明する
- credit balancesを表示するcustomer portalを実装する
- next invoice previewで適用されたcreditsを確認する
Webhook signature verification fails
Webhook signature verification fails
- webhook secret keyが正しくない
- signature verification前にraw request bodyが変更された
- signature verification algorithmが間違っている
- dashboardの正しい
DODO_PAYMENTS_WEBHOOK_KEYを使用していることを確認する - 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
- subscription IDまたはproduct IDが無効
- subscriptionがactive stateではない
- required parametersが不足
- productがplan changesに利用できない
- subscriptionが存在し、activeであることを確認する
- product IDが有効で利用可能であることを確認する
- required parametersがすべて提供されていることを確認する
- parameter requirementsについてAPI documentationを確認する
Immediate charge fails during plan change
Immediate charge fails during plan change
- 顧客のpayment methodの残高不足
- payment methodの期限切れまたは無効
- bankがtransactionを拒否
- fraud detectionがchargeをブロック
payment.failedwebhook eventsを適切に処理する- 顧客にpayment methodの更新を通知する
- 一時的なfailuresにretry logicを実装する
- failed immediate chargesでもplan changesを許可することを検討する
Subscription on hold after plan change
Subscription on hold after plan change
on_hold stateに移行するWhat happens:
プラン変更の請求に失敗すると、subscriptionは自動的に on_hold stateになります。payment methodが更新されるまで、subscriptionは自動的にrenewされません。Solution:payment methodを更新してsubscriptionをreactivateしますプラン変更の失敗後、 on_hold stateのsubscriptionをreactivateするには:- payment methodを更新:Update Payment Method APIを使用
- Automatic charge creation:APIが残りの未払い額に対するchargeを自動作成
- Invoice generation:chargeのinvoiceを生成
- Payment processing:新しいpayment methodでpaymentを処理
- Reactivation:payment成功後、subscriptionを
activestateへreactivate
subscription.on_hold:Subscription placed on hold(plan change charge fails時に受信)payment.succeeded:Payment for remaining dues succeeded(payment method更新後)subscription.active:Payment成功後にsubscription reactivated
- plan change chargeが失敗したら直ちに顧客へ通知する
- payment methodの更新方法を明確に案内する
- reactivation statusを追跡するためwebhook eventsを監視する
- 一時的なpayment failuresに対するautomatic retry logicの実装を検討する
Update Payment Method API Reference
実装のテスト
サブスクリプションのプラン変更実装を十分にテストします:Set up test environment
- test API keysとtest productsを使用する
- 異なるplan typesでtest subscriptionsを作成する
- test webhook endpointを設定する
- monitoringとloggingを設定する
Test different proration modes
- さまざまなbilling cycle positionsで
prorated_immediatelyをテストする - アップグレードとダウングレードで
difference_immediatelyをテストする - billing cyclesをリセットするため
full_immediatelyをテストする - no-charge/no-credit plan switchesで
do_not_billをテストする - credit calculationsが正しいことを確認する
Test webhook handling
- 関連するすべてのwebhook eventsが受信されることを確認する
- webhook signature verificationをテストする
- duplicate webhook eventsを適切に処理する
- webhook processing failure scenariosをテストする
Test error scenarios
- invalid subscription IDsでテストする
- expired payment methodsでテストする
- network failuresとtimeoutsをテストする
- insufficient fundsでテストする
Monitor in production
- failed plan changesのalertを設定する
- webhook processing timesを監視する
- plan change success ratesを追跡する
- plan change issuesに関するcustomer support ticketsを確認する
Error Handling
実装で一般的なAPI errorsを適切に処理します:HTTP Status Codes
200 OK
200 OK
payment_id、payment_link、client_secret、expires_on を含む ChangePlanResponse です。4つすべてがnullableであるため、通常のoff-session changeではbodyは {} としてserializeされます。成功した collect_via_payment_link requestでは値が設定され、checkout handlesが返されます。Collecting Payment via a Checkout Linkを参照してください。on_payment_failure=prevent_change の場合、payment成功までplan changeはpendingのままです。400 Bad Request
400 Bad Request
409 Conflict
409 Conflict
PendingPlanChangeExists)。scheduled changeの場合は、新しいものをsubmitする前に DELETE /subscriptions/{subscription_id}/change-plan/scheduled でキャンセルしてください。pending payment-link changeにはcancel endpointがありません。顧客が支払うかlinkの期限が切れると、subscriptionは新しいplan-change requestを受け付けます。422 Unprocessable Entity
422 Unprocessable Entity
collect_via_payment_link の対象外です。businessでcapabilityが有効になっていない、effective_at が immediately ではない、または on_payment_failure が prevent_change ではない可能性があります。Requirementsを参照してください。存在しない、またはaccountに属していないsubscription IDには、NOT_FOUND codeを含む 404 が返されます。500 Internal Server Error
500 Internal Server Error
Error Response Format
Errorsは、code と、人間が読める message を含むJSON bodyを返します:
Next Steps
- Change Plan APIを確認する
- Credit-Based Billingを確認する
subscription.on_holdのalertsを実装する- Webhook Integration Guideを確認する