Skip to main content

概览

按需订阅允许您一次性授权客户的支付方式,然后在需要时收取可变金额,而不是固定的日程表。所有账户都可使用此功能,无需审批。 使用本指南:
  • 创建按需订阅(授权带有可选初始价格的授权)
  • 通过自定义金额触发后续收费
  • 使用webhook跟踪结果
有关一般订阅设置,请参阅订阅集成指南

先决条件

  • Dodo Payments商家账户和API密钥
  • 配置的webhook密钥和接收事件的端点
  • 目录中的订阅产品
本指南通过结账会话创建按需订阅(POST /checkouts),此会话始终返回托管的checkout_url。将客户重定向到此处以批准授权,并设置return_url为他们应在批准后到达的位置。

按需如何运作

  1. 您使用on_demand对象创建订阅以授权支付方式,并可选择收取初始费用。
  2. 随后,您可以使用专用的收费端点根据该订阅创建自定义金额的收费。
  3. 您可以监听webhook(例如,payment.succeededpayment.failed)来更新您的系统。

创建按需订阅

端点:POST /checkouts 关键请求字段(正文):
请查看创建结账会话

创建按需订阅

Success

按需订阅的收费

授权授权后,按需创建所需的费用。 端点:POST /subscriptions/{subscription_id}/charge 关键请求字段(正文):
integer
必填
收费金额(以最小货币单位表示)。示例:要收取$25.00,请传递2500
string
可选的收费货币覆盖。
string
可选的描述覆盖。
boolean
如果为真,在product_price中包含自适应货币费用。如果为假,则费用将被追加在顶部。
object
指定如何使用客户的钱包余额来结算此笔扣款。
object
付款的其他 metadata。如果省略,则使用 subscription metadata。
Success
对非按需 subscription 进行扣款可能会失败。请确保 subscription 的详情中包含 on_demand: true,然后再进行扣款。

处理扣款失败

当对按需 subscription 的扣款失败时,接下来如何处理由你决定。与定期 subscription 不同——定期 subscription 的续期失败后会停止后续自动计费——按需 subscription 在失败后仍可继续扣款。你可以根据自己的重试逻辑再次调用扣款 endpoint。

失败时会发生什么

1

Charge attempt fails

POST /subscriptions/{subscription_id}/charge 请求要么返回错误响应,要么异步完成,并发送包含拒付原因的 payment.failed webhook。
2

Subscription may transition to on_hold

subscription 可能会进入 on_hold 状态,并发送 subscription.on_hold webhook(参见 Subscription States → On Hold)。这是一种信号,而不是锁定状态。对于按需 subscription,on_hold 不会阻止你再次扣款
3

Retry the charge (your call)

对于按需流程,Dodo 不会自动重试。你可以随时再次调用 POST /subscriptions/{subscription_id}/charge 进行重试。请应用下方的安全重试策略——使用指数退避、跳过硬拒付并避免突发式重试——以免重试被我们的欺诈和风险系统标记。
4

Optionally, ask the customer for a new payment method

如果由于 payment method 本身存在问题(卡片过期、账户已关闭等)而导致重试持续失败,请使用 POST /subscriptions/{subscription_id}/update-payment-method 向客户收集新的 payment method。成功后,subscription 会返回 active,并依次发送 payment.succeededsubscription.active webhook。
按需与定期的区别:对于定期 subscription,Dodo 会执行自身的续期重试和催收。对于按需 subscription,重试策略由你负责,因为只有你知道下一次扣款应在何时发生(它由使用量事件驱动,而不是日历驱动)。

按需扣款失败时的 webhook 顺序

事件 3 和 4 仅在后续扣款成功后触发。

重试责任

Dodo Payments 不会自动重试失败的按需扣款。重试策略由你负责。请遵循下方的安全重试指南,避免被我们的欺诈检测系统标记为盗刷测试。
Subscription Dunning——内置的邮件恢复序列——仅适用于定期 subscription 的失败续期付款以及客户发起的取消。它并非为按需扣款失败而设计。当你判断 payment method 需要更新时,请直接与客户沟通(例如通过事务性邮件或应用内提示)。

付款重试

我们的欺诈检测系统可能会阻止激进的重试模式(并将其标记为潜在的盗刷测试)。请遵循安全重试策略。
突发式重试模式可能会被我们的风险系统和处理方标记为欺诈或疑似盗刷测试。请避免集中重试,并遵循下方的退避计划和时间对齐指南。

安全重试策略的原则

  • 退避机制:在重试之间使用指数退避。
  • 重试次数限制:限制总重试次数(最多 3–4 次尝试)。
  • 智能筛选:仅对可重试的失败进行重试(例如网络错误、发卡行错误、余额不足);绝不重试硬拒付。
  • 防止盗刷测试:不要重试诸如 DO_NOT_HONORSTOLEN_CARDLOST_CARDPICKUP_CARDFRAUDULENTAUTHENTICATION_FAILURE 等失败。
  • 改变 metadata(可选):如果你维护自己的重试系统,可通过 metadata 区分重试(例如 retry_attempt)。

建议的重试计划(subscriptions)

  • 第 1 次尝试:创建扣款时立即执行
  • 第 2 次尝试:3 天后
  • 第 3 次尝试:再过 7 天(共 10 天)
  • 第 4 次尝试(最后一次):再过 7 天(共 17 天)
最后一步:如果仍未付款,请根据你的策略将 subscription 标记为未付款或取消。请在此期间通知客户更新其 payment method。

避免突发式重试;与授权时间对齐

  • 将重试锚定到最初的授权时间戳,以避免整个客户组合出现“突发式”行为。
  • 示例:如果客户今天下午 1:10 开始试用或 mandate,请根据退避计划在后续日期的下午 1:10 安排重试(例如 +3 天 → 下午 1:10,+7 天 → 下午 1:10)。
  • 或者,如果你存储了上次成功付款的时间 T,请将下一次尝试安排在 T + X days,以保持时间对齐。
时区和 DST:使用一致的时间标准进行调度,仅在显示时进行转换,以保持时间间隔。

不应重试的拒付代码

  • STOLEN_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_CARD
如需查看完整的拒付原因列表以及这些原因是否可由用户修正,请参阅 Transaction Failures 文档。
仅对软性/临时问题进行重试(例如 insufficient_fundsissuer_unavailableprocessing_error、网络超时)。如果相同的拒付重复出现,请暂停后续重试。

实施指南(无代码)

  • 使用能够持久化精确时间戳的 scheduler/queue;在准确的时间偏移处计算下一次尝试(例如 T + 3 days,在相同的 HH:MM 执行)。
  • 维护并参考上次成功付款的时间戳 T 来计算下一次尝试;不要让多个 subscription 在同一时刻集中重试。
  • 始终评估上次拒付原因;对于上方跳过列表中的硬拒付,停止重试。
  • 限制每位客户和每个账户的并发重试次数,防止意外激增。
  • 主动沟通:在下一次计划尝试前,通过电子邮件/SMS 通知客户更新其 payment method。
  • 仅将 metadata 用于可观测性(例如 retry_attempt);绝不要通过轮换无关字段来试图“规避”欺诈/风险系统。

取消

按需 subscription 的取消流程与定期 subscription 不同,因为没有固定的计费周期可用于确定立即结束日期。

Customer Portal 行为

当客户从 Customer Portal 取消按需 subscription 时,默认情况下,取消操作会安排在下一计费日期执行。按需 subscription 不会显示立即取消选项。 原因在于:按需 subscription 没有可预测的周期性续期日期——下一次扣款时间完全由你的使用量事件驱动。在下一计费日期取消,可以让 mandate 保持有效直到周期边界,从而仍可对正在处理的使用量进行扣款,然后干净地结束 subscription。 客户确认取消后:
  • subscription 保持 active 状态,并可通过 POST /subscriptions/{id}/charge 继续扣款,直到计划的取消日期。
  • subscription 上的 cancel_at_next_billing_date 被设置为 true
  • 取消生效时会发送 subscription.cancelled webhook。
如果你需要立即结束 subscription(例如响应退款或支持请求),请通过 API 以编程方式取消,而不要依赖 Customer Portal 流程。

以编程方式取消

你可以随时通过 API 取消按需 subscription。取消是立即执行还是计划执行,由你控制。 Endpoint:PATCH /subscriptions/{subscription_id}
将 subscription 的 status 设置为 cancelled,即可立即结束 subscription。mandate 将被撤销,之后无法再创建扣款。
cURL

取消时的 Webhooks

要在处理 webhook 时区分按需取消和定期 subscription 取消,请检查 subscription 的 on_demand 标志。

使用 webhooks 跟踪结果

实施 webhook 处理,以跟踪客户旅程。请参阅 Implementing Webhooks
  • subscription.active:mandate 已授权且 subscription 已激活
  • subscription.failed:创建失败(例如 mandate 失败)
  • subscription.on_hold:subscription 被置于暂停状态(例如未付款状态)
  • subscription.cancelled:subscription 已完全取消(参见取消
  • payment.succeeded:扣款成功
  • payment.failed:扣款失败
对于按需流程,请重点关注 payment.succeededpayment.failed,以核对基于使用量的扣款。当 payment.failed 后紧接着出现 subscription.on_hold 时,请参阅处理扣款失败以恢复 subscription。

测试和后续步骤

1

Create in test mode

使用 test API key 创建 subscription,然后打开返回的 checkout_url 并完成 mandate。
2

Trigger a charge

使用较小的 product_price 调用扣款 endpoint(例如 100),并确认收到 payment.succeeded
3

Go live

验证事件和内部状态更新后,切换到 live API key。

故障排查

  • 422 Invalid Request:确保在创建时提供 on_demand.mandate_only,并在扣款时提供 product_price
  • 货币错误:如果覆盖 product_currency,请确认该货币受你的账户和客户支持。
  • 未收到 webhooks:验证 webhook URL 和签名密钥配置。
最后修改于 2026年8月6日