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
- 指定なし /
null— 新しい製品に適用可能な場合、preserve_on_plan_change=trueで既存の割引が保持されます。 [](空の配列) — すべての既存の割引がサブスクリプションから削除されます。["CODE_A", "CODE_B", ...]— 既存の割引をこのスタックセットで置き換えます。
discount_codes を推奨。このフィールドは後方互換性のために機能しますが、同じリクエストで discount_codes と組み合わせることはできません。immediately(デフォルト): プラン変更をすぐに適用next_billing_date: 次の請求日に変更をスケジュール。顧客は請求期間が終了するまで現在のプランを保持。
next_billing_date を使用し、請求期間が終了するまで顧客は現在のプラン特典を保持します。Handle Webhook Events
subscription.active: プラン変更成功、サブスクリプションが更新されましたsubscription.plan_changed: サブスクリプションプランが変更されました(アップグレード/ダウングレード/アドオンの更新)subscription.on_hold: プラン変更課金が失敗し、サブスクリプションが一時停止されましたpayment.succeeded: プラン変更の即時課金が成功しましたpayment.failed: 即時課金が失敗しました
Update Your Application State
- 新しいプランに基づいて機能を付与/剥奪
- 顧客ダッシュボードを新しいプランの詳細で更新
- プラン変更に関する確認メールを送信
- 監査目的で請求の変更をログ
プラン変更のプレビュー
プラン変更を確定する前に、プレビューAPIを使用して顧客に正確に課金される金額を示します:- Node.js SDK
- Python SDK
プラン変更API
Change Plan APIを使用して、アクティブなサブスクリプションの製品、数量、およびプロレーションの動作を変更します。クイックスタート例
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
invoice_idやpayment_idのようなフィールドは、プラン変更中に即時課金や請求書が作成された場合のみ返されます。結果を確認するために常にウェブフックイベント(例:payment.succeeded、subscription.plan_changed)に依存します。アドオンの管理
サブスクリプションプランを変更する際、アドオンも変更できます:割引コードの適用
サブスクリプションプランを変更する際に、1つまたは複数のスタック型割引コードを適用できます(最大20、配列順で適用)。アップグレードや移行時のプロモーション価格提供に便利です。- Node.js SDK
- Python SDK
- HTTP
プラン変更時の割引の動作
discount_codes 値 | 動作 |
|---|---|
指定なし / null | 新しい製品に適用可能な場合、preserve_on_plan_change=true で既存の割引が自動的に保持されます。 |
[] (空の配列) | 既存のすべての割引がサブスクリプションから削除されます。 |
["CODE_A", "CODE_B", ...] | このスタックセットで既存の割引を置き換え、配列順に検証および適用されます。 |
discount_code フィールドは非推奨ですが、後方互換性のために機能します。既存の統合はすぐに変更する必要はありません。同じリクエストで discount_codes と組み合わせることはできません。便利なときに配列形式に移行してください。プロレーションモード
プランを変更する際の顧客への請求方法を選択します:prorated_immediately
- 現在のサイクルの部分差額に対する課金
- トライアル期間中の場合、即時に課金され、新しいプランに変更されます
- ダウングレード:将来の更新に適用されるプロレーションされたクレジットを生成する可能性があります
full_immediately
- 新しいプランの全額を即時に課金
- 古いプランの残り時間を無視
difference_immediatelyを使用してダウングレードによって作成されたクレジットはサブスクリプションに限定され、Credit-Based Billingの権利とは異なります。それらは自動的に同じサブスクリプションの将来の更新に適用され、他のサブスクリプション間で転送されません。difference_immediately
- アップグレード:旧プランと新プランの価格差を即時に課金
- ダウングレード:残価を内部クレジットとしてサブスクリプションに追加し、更新時に自動適用
do_not_bill
- 課金やクレジットは計算されません
- 顧客は請求調整なしで即時に新しいプランに切り替わります
- 請求サイクルは変更されません
- コスト差吸収、無償移行、親切なスイッチに最適
| 機能 | prorated_immediately | difference_immediately | full_immediately | do_not_bill |
|---|---|---|---|---|
| アップグレード課金 | 残り日数に対するプロレーション差額 | プラン間の正価差額 | 新プランの全額 | 課金なし |
| ダウングレードクレジット | 残り日数に対するプロレーションクレジット | 正価差額をクレジットとして | クレジットなし | クレジットなし |
| 請求サイクル | 変更なし | 変更なし | 今日にリセット | 変更なし |
| トライアルの動作 | トライアル終了、即時課金 | トライアル終了、即時課金 | トライアル終了、全額課金 | トライアル終了、課金なし |
| 最適な用途 | 公正な時間ベースの請求 | 簡単なアップグレード/ダウングレードの計算 | 請求サイクルのリセット | 無償移行や親切なスイッチ |
| 複雑さ | 中(時間計算) | 低(簡単な引き算) | 低(全額課金) | なし |
例シナリオ
次の基準数値を一貫して使用します:- 現在のプラン:Basic($30/月)
- アップグレードの目標:Pro($80/月)
- ダウングレードの目標(Proから):Starter($20/月)
- 請求サイクル:30日、開始日1月1日
- プラン変更は1月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
各モードが請求を処理する方法
支払い失敗の対応
プラン変更の支払いが失敗した場合に何が起こるかをon_payment_failure パラメータを使用して制御します。
支払い失敗モード
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- プラン変更は「保留」としてマークされます
- 顧客は現在のプランにアクセスし続けます
- サブスクリプションが成功した支払い後にだけ
active状態に移行します - 支払いの確認を通じて機能を強化する場合に便利
on_payment_failure パラメータはダッシュボードで設定されたビジネスレベルのデフォルト設定を使用します。各モードの使用タイミング
| シナリオ | 推奨モード | 理由 |
|---|---|---|
| プレミアム機能へのアップグレード | prevent_change | アクセスを提供する前に支払いを確認する |
| 数量増加(座席数増加) | prevent_change | 支払いなしでの利用を防ぐ |
| プランのダウングレード | apply_change | 顧客は支出を減らしています |
| 信頼できるエンタープライズ顧客 | apply_change | 支払いのリスクが低い |
| トライアルから有料への変換 | prevent_change | 重要な支払いの瞬間 |
ウェブフックの処理
ウェブフックを通じてサブスクリプションの状態を追跡し、プランの変更と支払いを確認します。処理するイベントタイプ
subscription.active: サブスクリプションがアクティブ化されましたsubscription.plan_changed: サブスクリプションプランが変更されました(アップグレード/ダウングレード/アドオンの変更)subscription.on_hold: 課金失敗、サブスクリプションが一時停止subscription.renewed: 更新成功payment.succeeded: プラン変更または更新の支払いが成功payment.failed: 支払い失敗
署名の検証とインテントの処理
- Next.js Route Handler
- Express.js
ベストプラクティス
信頼性のあるサブスクリプションプラン変更のための推奨事項に従ってください:プラン変更戦略
- 徹底的にテスト: 本番前に常にプラン変更をテストモードでテストする
- プロレーションを慎重に選択: ビジネスモデルに合ったプロレーションモードを選ぶ
- 失敗を丁寧に処理: 適切なエラーハンドリングとリトライロジックを実装する
- 成功率を監視: プラン変更の成功/失敗率を追跡し、問題を調査する
ウェブフックの実装
- 署名を検証する: ウェブフックの署名を常に確認して正当性を保証する
- 冪等性を実装: 重複するウェブフックイベントを丁寧に処理する
- 非同期で処理する: ウェブフックの応答を重い操作でブロックしない
- すべてをログ: デバッグおよび監査のために詳細なログを維持する
ユーザーエクスペリエンス
- 明確に伝える: 顧客に請求の変更とタイミングを通知する
- 確認を提供: 成功したプラン変更の確認メールを送付する
- エッジケースを処理する: トライアル期間、プロレーション、支払い失敗を考慮する
- UIを即時更新する: アプリケーションのインターフェイスでプラン変更を反映する
一般的な問題と解決策
サブスクリプションプラン変更中に遭遇する典型的な問題を解決します:Charge created but subscription not updated
Charge created but subscription not updated
- ウェブフックの処理が失敗または遅延した
- ウェブフック受信後にアプリケーションの状態が更新されていない
- 状態更新中のデータベーストランザクションの問題
- リトライロジックを使用した堅牢なウェブフック処理を実装する
- 状態更新用に冪等操作を使用する
- 見逃したウェブフックイベントを検出して警告するモニタリングを追加する
- ウェブフックエンドポイントのアクセス性と応答を確認する
Credits not applied after downgrade
Credits not applied after downgrade
- プロレーションモードの期待値:ダウングレードは
difference_immediatelyでプラン価格の差額全体をクレジットし、prorated_immediatelyはサイクルの残り時間に基づいてプロレーションされたクレジットを生成 - クレジットはサブスクリプション専用で、サブスクリプション間で転送されない
- 顧客ダッシュボードにおけるクレジット残高の表示がない
- 自動クレジットが必要な場合、ダウングレードに
difference_immediatelyを使用する - クレジットは同じサブスクリプションの将来の更新にのみ適用されると顧客に説明する
- クレジット残高を表示する顧客ポータルを実装する
- 適用されたクレジットを見るために次の請求書プレビューを確認する
Webhook signature verification fails
Webhook signature verification fails
- ウェブフックシークレットキーが不正
- JSONパースミドルウェアの前に生のリクエストボディが変更された
- 誤った署名検証アルゴリズム
- ダッシュボードから正しい
DODO_WEBHOOK_SECRETを使用しているか確認する - どのJSONパースミドルウェアの前にも生のリクエストボディを読み取る
- プラットフォーム用の標準ウェブフック検証ライブラリを使用する
- 開発環境でのウェブフック署名検証をテストする
Plan change fails with 422 error
Plan change fails with 422 error
- 無効なサブスクリプションIDや製品ID
- サブスクリプションがアクティブ状態ではない
- 必須パラメータが欠如
- プラン変更のための製品が利用できない
- サブスクリプションが存在し、アクティブであることを確認する
- 製品IDが有効であり利用可能であることを確認する
- 必須パラメータがすべて提供されていることを確認する
- パラメータ要件に関するAPIドキュメントを確認する
Immediate charge fails during plan change
Immediate charge fails during plan change
- 顧客の支払い方法に十分な資金がない
- 支払い方法が期限切れまたは無効
- 銀行が取引を拒否
- 不正検出が課金をブロック
- 処理する
payment.failedウェブフックイベントを適切に対処する - 顧客に支払い方法を更新するよう通知する
- 一時的な障害の場合にリトライロジックを実装する
- 失敗した即時課金でもプラン変更を許可することを検討する
Subscription on hold after plan change
Subscription on hold after plan change
on_hold 状態に移行する何が起こるか:
プラン変更課金が失敗すると、サブスクリプションは自動的に on_hold 状態になります。支払い方法が更新されるまでサブスクリプションは自動で更新されません。解決策: 支払い方法を更新してサブスクリプションを再活性化支払い方法を更新し、失敗したプラン変更後に on_hold 状態からサブスクリプションを再活性化するには:- 支払い方法を更新するためにUpdate Payment Method APIを使用
- 自動チャージ作成: APIは自動的に未払い分のチャージを作成
- 請求書の発行: チャージに対して請求書を発行
- 支払い処理: 新しい支払い方法を使用して支払いを処理
- 再活性化: 支払いが成功すると、サブスクリプションが成功の
active状態に再活性化されます
subscription.on_hold: プラン変更課金が失敗し、サブスクリプションが保留される(受信時)payment.succeeded: 支払い方法の更新後に残余額の支払いが成功subscription.active: 支払い成功後にサブスクリプションが再活性化
- プラン変更課金が失敗した際には顧客に即座に通知する
- 支払い方法の更新方法を明確に説明する
- ウェブフックイベントを監視して再活性化状態を追跡する
- 一時的な支払い失敗の自動リトライロジックを実装することを検討
Update Payment Method API Reference
実装のテスト
サブスクリプションプラン変更の実装を徹底的にテストするために、以下の手順に従ってください:Set up test environment
- テストAPIキーとテスト製品を使用する
- 異なるプランタイプでテストサブスクリプションを作成する
- テストウェブフックエンドポイントを設定する
- モニタリングとログを設定する
Test different proration modes
- 様々な請求サイクルの位置で
prorated_immediatelyをテストする - アップグレードとダウングレードのために
difference_immediatelyをテストする - 請求サイクルをリセットするために
full_immediatelyをテストする - 無課金/無クレジットのプランスイッチのために
do_not_billをテストする - クレジット計算が正しいことを確認する
Test webhook handling
- 関連するすべてのウェブフックイベントを受信することを確認する
- ウェブフック署名の検証をテストする
- 重複したウェブフックイベントを丁寧に扱う
- ウェブフック処理失敗のシナリオをテストする
エラーハンドリング
実装における一般的なAPIエラーを丁寧に処理します:HTTPステータスコード
200 OK
200 OK
400 Bad Request
400 Bad Request
401 Unauthorized
401 Unauthorized
404 Not Found
404 Not Found
422 Unprocessable Entity
422 Unprocessable Entity
500 Internal Server Error
500 Internal Server Error
エラーレスポンスフォーマット
次のステップ
- Change Plan APIをレビューする
- Credit-Based Billingを探索する
subscription.on_holdのためのアラートを実装する- Webhook Integration Guideをチェックアウトする