概要
オンデマンドサブスクリプションでは、顧客の支払い方法を一度承認すると、固定スケジュールではなく、必要なときにいつでも変動する金額を請求できます。この機能はすべてのアカウントで利用でき、承認は必要ありません。 このガイドでは、次の方法を説明します。- オンデマンドサブスクリプションを作成する(任意の初回価格で 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
- Node.js SDK
- Python SDK
- Go SDK
- cURL
Success
失敗した請求の処理
オンデマンドサブスクリプションに対する請求が失敗した場合、次に何をするかはあなたが決定します。スケジュールされたサブスクリプションでは、更新に失敗すると以降の自動課金が停止しますが、オンデマンドサブスクリプションは失敗後も請求可能な状態を維持します。独自の retry ロジックの一部として、charge endpoint を再度呼び出せます。失敗時の動作
1
Charge attempt fails
POST /subscriptions/{subscription_id}/charge request は、error response を返すか、非同期で完了して、decline reason を含む payment.failed webhook を発行します。2
Subscription may transition to on_hold
subscription が
on_hold state に移行し、subscription.on_hold webhook を発行することがあります(Subscription States → On Holdを参照)。これはシグナルであり、ロックではありません。オンデマンドサブスクリプションでは、on_hold によって再度請求できなくなることはありません。3
Retry the charge (your call)
オンデマンドフローでは、Dodo は自動 retry を行いません。
POST /subscriptions/{subscription_id}/charge はいつでも再度呼び出して retry できます。以下の safe retry policy を適用してください。exponential backoff を使用し、hard decline をスキップし、burst パターンを避けることで、retry が当社の fraud および risk system によって検知されないようにします。4
Optionally, ask the customer for a new payment method
支払い方法自体に問題があるため retry が続けて失敗する場合(カードの有効期限切れ、アカウント閉鎖など)は、
POST /subscriptions/{subscription_id}/update-payment-method を使用して、顧客から新しい支払い方法を収集します。成功すると subscription は active に戻り、payment.succeeded に続いて subscription.active webhook が発行されます。オンデマンドとスケジュールの違い:スケジュールされたサブスクリプションでは、Dodo が独自の更新 retry と dunning を実行します。オンデマンドサブスクリプションでは、次の請求をいつ行うべきかを把握しているのはあなただけです(カレンダーではなく usage event に基づくため)、retry ポリシーをあなたが管理します。
オンデマンド請求が失敗した場合の webhook sequence
3 と 4 の event は、後続の請求が成功した場合にのみ発生します。
retry の責任
Subscription Dunning(組み込みの email recovery sequence)は、スケジュールされたサブスクリプションの失敗した renewal payment と、顧客が開始した cancellation を対象とします。オンデマンド請求の失敗向けには設計されていません。支払い方法を更新する必要があると判断した場合は、顧客に直接(transactional email やアプリ内 prompt などで)連絡してください。Payment retries
当社の fraud detection system は、積極的な retry パターンをブロックすることがあり(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(任意):独自の retry system を運用している場合は、metadata(例:
retry_attempt)で retry を区別します。
推奨 retry schedule(subscriptions)
- 1 回目:charge の作成時に即時実行
- 2 回目:3 日後
- 3 回目:さらに 7 日後(合計 10 日後)
- 4 回目(最終):さらに 7 日後(合計 17 日後)
burst retry を避け、承認時刻に合わせる
- 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 を使用し、interval を維持するため、表示時のみ変換します。
retry すべきでない decline codes
STOLEN_CARDDO_NOT_HONORFRAUDULENTPICKUP_CARDAUTHENTICATION_FAILURELOST_CARD
decline reason の包括的な一覧と、ユーザーが修正可能かどうかについては、Transaction Failures のドキュメントを参照してください。
実装ガイドライン(コードなし)
- 正確な timestamp を永続化する scheduler/queue を使用し、時刻単位の offset(例:同じ HH:MM の
T + 3 days)で次の試行時刻を計算します。 - 最後に成功した支払いの timestamp
Tを保持・参照して次の試行を計算し、複数の subscription を同じ時刻に集中させないでください。 - 常に最後の decline reason を評価し、上記の skip list にある hard decline の retry を停止します。
- 偶発的な急増を防ぐため、顧客ごとおよびアカウントごとの同時 retry 数を制限します。
- 事前に連絡します。次回の scheduled attempt より前に、顧客へ email/SMS で支払い方法の更新を依頼してください。
- metadata は observability の目的にのみ使用し(例:
retry_attempt)、意味のない field を変更して fraud/risk system を「回避」しようとしないでください。
Cancellation
オンデマンドサブスクリプションでは、即時の終了日を基準にする固定の billing cycle がないため、スケジュールされたサブスクリプションとは異なる cancellation flow に従います。Customer Portal の動作
顧客が Customer Portal からオンデマンドサブスクリプションを cancel すると、デフォルトでは 次の billing date に cancellation がスケジュールされます。オンデマンドサブスクリプションでは、Cancel Now option は意図的に表示されません。 理由は、オンデマンドサブスクリプションには予測可能な定期更新日がなく、次の請求時刻が完全に usage event によって決まるためです。次の billing date に cancellation をスケジュールすることで、period boundary まで mandate を有効に保ち、進行中の usage を請求してから subscription を正常に終了できます。 顧客が cancellation を確認した後:- subscription は
activeのままとなり、scheduled cancellation date までPOST /subscriptions/{id}/chargeを介して引き続き請求できます。 - subscription の
cancel_at_next_billing_dateはtrueに設定されます。 - cancellation が有効になった時点で
subscription.cancelledwebhook が発行されます。
subscription を直ちに終了する必要がある場合(たとえば refund や support request への対応時)は、Customer Portal flow に頼らず、API を介して programmatically に cancel してください。
Programmatically に cancel する
API を介して、いつでもオンデマンドサブスクリプションを cancel できます。cancellation を即時に行うか、スケジュールするかを制御できます。 Endpoint: PATCH /subscriptions/{subscription_id}- Cancel immediately
- Cancel at next billing date
subscription の
status を cancelled に設定すると、直ちに終了します。mandate は revoked になり、それ以降の charge は作成できません。cURL
cancellation 時の webhook
webhook で結果を追跡する
顧客の journey を追跡するため、webhook handling を実装します。Implementing Webhooksを参照してください。- subscription.active:mandate が承認され、subscription が有効化された
- subscription.failed:作成に失敗した(例:mandate failure)
- subscription.on_hold:subscription が hold された(例:unpaid state)
- subscription.cancelled:subscription が完全に cancel された(Cancellationを参照)
- payment.succeeded:charge が成功した
- payment.failed:charge が失敗した
テストと次のステップ
1
Create in test mode
test API key を使用して subscription を作成し、返された
checkout_url を開いて mandate を完了します。2
Trigger a charge
小さな
product_price(例:100)で charge endpoint を呼び出し、payment.succeeded を受信したことを確認します。3
Go live
event と内部 state の更新を検証したら、live API key に切り替えます。
トラブルシューティング
- 422 Invalid Request:作成時に
on_demand.mandate_onlyが提供され、charge にproduct_priceが提供されていることを確認してください。 - Currency errors:
product_currencyを override する場合、アカウントと顧客でサポートされていることを確認してください。 - webhook を受信できない:webhook URL と signature secret の設定を確認してください。