概要
オンデマンドサブスクリプションでは、顧客の支払い方法を一度承認すると、固定スケジュールではなく、必要なときにいつでも変動する金額を請求できます。この機能はすべてのアカウントで利用でき、承認は必要ありません。 このガイドでは、次の方法を説明します。- オンデマンドサブスクリプションを作成する(任意の初回価格で mandate を承認)
- カスタム金額で後続の請求をトリガーする
- webhook を使用して結果を追跡する
前提条件
- Dodo Payments merchant account と API key
- webhook secret が設定され、イベントを受信する endpoint があること
- カタログにサブスクリプション product があること
オンデマンドの仕組み
on_demandobject を使用して subscription を作成し、支払い方法を承認して、必要に応じて初回請求を回収します。- 後から、専用の charge endpoint を使用し、カスタム金額でその subscription に対する charge を作成します。
- webhook(例:
payment.succeeded、payment.failed)をリッスンして、システムを更新します。
オンデマンドサブスクリプションを作成する
Endpoint: POST /checkouts 主要な request fields(body):Create Checkout Sessionで確認してください
オンデマンドサブスクリプションを作成する
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
オンデマンドサブスクリプションに請求する
mandate の承認後、必要に応じて charge を作成します。 Endpoint: POST /subscriptions/{subscription_id}/charge 主要な request fields(body):Charge request body parameters
Charge request body parameters
integer
必須
請求する金額(最小通貨単位)。例:$25.00 を請求するには、
2500 を渡します。string
この請求に対する任意の currency override。
string
この請求に対する任意の description override。
boolean
true の場合、Adaptive Currency の手数料を
product_price に含めます。false の場合、手数料は上乗せされます。object
顧客のウォレット残高をこの請求の決済に使用する方法を指定します。
object
支払いに関する追加のメタデータ。省略した場合は、サブスクリプションのメタデータが使用されます。
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
請求失敗への対応
オンデマンドサブスクリプションへの請求が失敗した場合、次に何をするかはあなたが決定します。スケジュールされたサブスクリプションでは、更新に失敗すると以降の自動請求が停止しますが、オンデマンドサブスクリプションは失敗後も請求できます。独自の retry ロジックの一部として、請求エンドポイントを再度呼び出せます。失敗時の動作
1
Charge attempt fails
POST /subscriptions/{subscription_id}/charge リクエストはエラーレスポンスを返すか、非同期で完了し、拒否理由を含む payment.failed webhook を発行します。2
Subscription may transition to on_hold
サブスクリプションは
on_hold 状態に移行し、subscription.on_hold webhook を発行することがあります(Subscription States → On Hold を参照)。これはシグナルであり、ロックではありません。オンデマンドサブスクリプションでは、on_hold になっても、再度請求することを妨げません。3
Retry the charge (your call)
オンデマンドフローでは、Dodo は自動 retry を行いません。いつでも
POST /subscriptions/{subscription_id}/charge を再度呼び出して retry できます。下記の 安全な retry ポリシー に従い、exponential backoff を使用し、hard decline をスキップして、burst パターンを避けてください。これにより、retry が当社の fraud および risk システムによってフラグ付けされるのを防げます。4
Optionally, ask the customer for a new payment method
支払い方法自体に問題があるために retry が繰り返し失敗する場合(カードの有効期限切れ、アカウントの閉鎖など)は、
POST /subscriptions/{subscription_id}/update-payment-method を使用して、顧客から新しい支払い方法を取得します。成功すると、サブスクリプションは active に戻り、続けて payment.succeeded および subscription.active webhook が発行されます。オンデマンドとスケジュール型の違い:スケジュールされたサブスクリプションでは、Dodo が独自に更新 retry と督促を実行します。オンデマンドサブスクリプションでは、次の請求をいつ行うべきかを把握しているのはあなただけです(カレンダーではなく利用イベントによって決まるため)、retry ポリシーを管理します。
オンデマンド請求が失敗した場合の webhook シーケンス
Event 3 と 4 は、後続の請求が成功した後にのみ発行されます。
retry の責任
Subscription Dunning — 組み込みのメールによる回収シーケンス — は、スケジュールされたサブスクリプションの 更新 支払いの失敗と、顧客が開始したキャンセルを対象としています。オンデマンド請求の失敗向けには設計されていません。支払い方法を更新する必要があると判断した場合は、顧客に直接(transactional email やアプリ内プロンプトなどで)連絡してください。支払いの retry
当社の fraud detection システムは、積極的な retry パターンをブロックすることがあり(potential card testing としてフラグ付けする場合もあります)、安全な retry ポリシーに従ってください。安全な retry ポリシーの原則
- Backoff mechanism:retry の間隔には exponential backoff を使用します。
- Retry limits:retry の合計回数を制限します(最大 3~4 回)。
- Intelligent filtering:retry 可能な失敗(network/issuer error、残高不足など)の場合にのみ retry し、hard decline は決して retry しません。
- Card testing prevention:
DO_NOT_HONOR、STOLEN_CARD、LOST_CARD、PICKUP_CARD、FRAUDULENT、AUTHENTICATION_FAILUREなどの失敗は retry しないでください。 - Vary metadata (optional):独自の retry システムを管理している場合は、メタデータ(例:
retry_attempt)で retry を区別します。
推奨 retry スケジュール(サブスクリプション)
- 1 回目:請求を作成した直後
- 2 回目:3 日後
- 3 回目:さらに 7 日後(合計 10 日後)
- 4 回目(最終):さらに 7 日後(合計 17 日後)
burst retry を避け、authorization 時刻に合わせる
- portfolio 全体で「burst」動作が発生しないよう、retry の基準を元の authorization timestamp にします。
- 例:顧客が本日午後 1:10 に trial または mandate を開始した場合、backoff(例:+3 日 → 午後 1:10、+7 日 → 午後 1:10)に従い、後続の retry を各日の午後 1:10 にスケジュールします。
- または、最後に成功した支払い時刻
Tを保存している場合は、時刻を合わせるため、次の試行をT + X daysにスケジュールします。
Time-zone と DST:スケジュールには一貫した time standard を使用し、間隔を維持するため、表示時にのみ変換します。
retry すべきでない decline code
STOLEN_CARDDO_NOT_HONORFRAUDULENTPICKUP_CARDAUTHENTICATION_FAILURELOST_CARD
decline reason の包括的な一覧と、ユーザーが修正可能かどうかについては、Transaction Failures ドキュメントを参照してください。
実装ガイドライン(コードなし)
- 正確な timestamp を永続化する scheduler/queue を使用し、正確な時刻の offset(例:同じ HH:MM の
T + 3 days)で次の試行を計算します。 - 最後に成功した支払いの timestamp
Tを保持・参照して次の試行を計算します。複数のサブスクリプションを同じ時刻に集中させないでください。 - 常に最後の decline reason を評価し、上記の skip list にある hard decline の retry を停止します。
- 意図しない surge を防ぐため、顧客ごと、アカウントごとに同時 retry 数を制限します。
- 事前に連絡します:次回のスケジュールされた試行の前に、支払い方法を更新するよう顧客へ email/SMS で通知します。
- メタデータは observability のみに使用し(例:
retry_attempt)、意味のないフィールドをローテーションして fraud/risk システムを「回避」しようとしないでください。
キャンセル
オンデマンドサブスクリプションでは、即時の終了日を決める基準となる固定の billing cycle がないため、スケジュールされたサブスクリプションとは異なるキャンセルフローに従います。Customer Portal の動作
顧客が Customer Portal からオンデマンドサブスクリプションをキャンセルすると、デフォルトではキャンセルが次回の billing date にスケジュールされます。オンデマンドサブスクリプションでは、Cancel Now オプションは意図的に表示されません。 理由は、オンデマンドサブスクリプションには予測可能な定期更新日がなく、次回の請求時刻が完全に利用イベントによって決まるためです。次回の billing date にキャンセルをスケジュールすることで、期間の境界まで mandate を有効なまま維持し、進行中の利用分を請求できるようにしてから、サブスクリプションを適切に終了できます。 顧客がキャンセルを確定した後:- サブスクリプションは
activeのままとなり、スケジュールされたキャンセル日までPOST /subscriptions/{id}/chargeを介して引き続き請求できます。 - サブスクリプションの
cancel_at_next_billing_dateにtrueが設定されます。 - キャンセルが有効になった時点で
subscription.cancelledwebhook が発行されます。
サブスクリプションを直ちに終了する必要がある場合(返金やサポートリクエストへの対応など)は、Customer Portal のフローに依存せず、API を介してプログラムでキャンセルしてください。
プログラムでキャンセルする
オンデマンドサブスクリプションは、いつでも API を介してキャンセルできます。キャンセルを即時に行うか、スケジュールするかを制御できます。 Endpoint: PATCH /subscriptions/{subscription_id}- Cancel immediately
- Cancel at next billing date
サブスクリプションの
status を cancelled に設定すると、直ちに終了します。mandate は revoke され、それ以降の請求は作成できません。cURL
キャンセル時の webhook
webhook で結果を追跡する
顧客の journey を追跡するため、webhook handling を実装します。Implementing Webhooks を参照してください。- subscription.active:Mandate が authorized になり、サブスクリプションが有効化された
- subscription.failed:作成に失敗した(例:mandate failure)
- subscription.on_hold:サブスクリプションが保留になった(例:unpaid state)
- subscription.cancelled:サブスクリプションが完全にキャンセルされた(Cancellation を参照)
- payment.succeeded:請求が成功した
- payment.failed:請求が失敗した
テストと次のステップ
1
Create in test mode
test API key を使用してサブスクリプションを作成し、返された
checkout_url を開いて mandate を完了します。2
Trigger a charge
少額の
product_price(例:100)を指定して請求エンドポイントを呼び出し、payment.succeeded を受信したことを確認します。3
Go live
Event と内部 state の更新を検証したら、live API key に切り替えます。
トラブルシューティング
- 422 Invalid Request:作成時に
on_demand.mandate_onlyが、請求時にproduct_priceが指定されていることを確認してください。 - Currency errors:
product_currencyを上書きする場合は、アカウントと顧客でサポートされていることを確認してください。 - No webhooks received:webhook URL と signature secret の設定を確認してください。