Skip to main content

Prerequisites

Before you start, you need:
  • A Dodo Payments merchant account
  • An API key from Developer → API Keys in the dashboard, stored in DODO_PAYMENTS_API_KEY
  • A webhook secret from Developer → Webhooks, stored in DODO_PAYMENTS_WEBHOOK_KEY
  • At least one subscription product created under Products
For more details, see Integration Guide Prerequisites.

API Integration

Checkout Sessions

Create a subscription by building a checkout session with your subscription product. The customer authorizes a payment method and the subscription activates when they complete checkout.
您可以在同一个 checkout session 中将订阅产品与一次性产品组合使用。这支持设置费、与 SaaS 搭配的硬件套装以及类似用例。有关示例,请参阅 Checkout Sessions。您还可以在一次 checkout 中销售两个或更多订阅产品。客户只需支付一次费用,即可为每个产品获得一个独立订阅,每个订阅都有自己的计费周期。此类购物车不能包含一次性产品。请参阅 Multi-Subscription Cart。

API 响应

响应包含一个 checkout_url:
将客户重定向到此 URL。客户授权支付方式后,订阅将激活。

Webhooks

当订阅事件发生时,Webhooks 会通知您的服务器。在 dashboard 的 Developer → Webhooks 下设置您的 endpoint。 如需设置 webhook endpoint,请参阅 Webhooks。

订阅事件类型

跟踪以下事件以管理订阅生命周期:
  1. subscription.active — 订阅已激活
  2. subscription.updated — 订阅中的某个字段发生更改
  3. subscription.on_hold — 续订或计划变更扣款失败
  4. subscription.failed — 订阅创建失败(终止状态;客户必须重新订阅)
  5. subscription.renewed — 周期性扣款成功
  6. subscription.past_due — 续订失败且宽限期已开始;客户会继续保留访问权限,直到 past_due_ends_at
  7. subscription.plan_changed — 计划已升级、降级或更改
  8. subscription.cancelled — 订阅已取消
  9. subscription.expired — 订阅已达到其期限结束时间
这些是核心事件。完整列表(包括 paused、unpaused 和 update_payment_method)请参阅 Subscription Webhooks。
使用 subscription.updated 获取有关任何订阅变更的实时通知,使应用状态保持同步,而无需轮询 API。

支付场景

成功支付流程 Webhook 序列取决于订阅是否包含试用期。 立即计费(0 个试用日):
  1. subscription.active:mandate 已授权,订阅已激活。
  2. payment.succeeded:确认首次扣款。预计在 checkout 后 2–10 分钟内收到此事件。
包含试用期:
  1. 试用期开始时(checkout): 支付方式获得授权后,subscription.active 触发。此时不会收取周期性扣款。 首次实际扣款会推迟到试用期结束。
  2. 试用期结束时: 系统会收取周期性金额,您会同时收到 payment.succeeded 和 subscription.renewed。
每次后续续订:
  • subscription.renewed:每个计费周期扣除续订款项时触发,始终与 payment.succeeded 一起发送。该事件还包含更新后的 next_billing_date。
每当订阅产品实际扣款时,您都会收到 subscription.renewed 和 payment.succeeded。请使用 subscription.renewed(而不是单独使用 payment.succeeded)作为延长下一周期访问权限的信号。
支付失败场景
  1. 订阅失败
  • subscription.failed - 由于创建 mandate 失败,订阅创建失败。
  • payment.failed - 表示支付失败。
  1. 订阅暂停
  • subscription.on_hold - 由于续订支付失败或计划变更扣款失败,订阅被暂停。如果您的业务设有宽限期,续订失败后订阅会先进入 past_due(subscription.past_due),只有在宽限期结束后才会进入 on_hold(或 cancelled,具体取决于您的宽限期设置)。请参阅 Subscription States。
  • 订阅暂停后,在更新支付方式之前不会自动续订。
最佳实践:为简化实现,我们建议主要跟踪订阅事件来管理订阅生命周期。
有关读取 error_code/error_message、决定何时重试以及向客户展示失败的完整流程,请参阅 Handle Payment Failures。

subscription.failed 与 subscription.on_hold

这两个事件很容易混淆,但处理方式完全不同:
subscription.failed 是终止状态。订阅无法重新激活。客户必须创建新订阅。此事件触发时,切勿授予权益。

处理暂停的订阅

当订阅进入 on_hold 状态时,您需要更新支付方式才能重新激活订阅。本节说明订阅何时会暂停以及如何处理。

订阅暂停的情况

在以下情况下,订阅会被暂停:
  • 续订支付失败:由于余额不足、卡片过期或银行拒绝,自动续订扣款失败
  • 计划变更扣款失败:升级或降级计划期间的立即扣款失败
  • 支付方式授权失败:无法为周期性扣款授权支付方式
处于 on_hold 状态的订阅不会自动续订。您必须更新支付方式才能重新激活订阅。

从暂停状态重新激活订阅

要将订阅从 on_hold 状态重新激活,请使用 Update Payment Method API。该 API 会自动执行以下操作:
  1. 为剩余应付款创建扣款
  2. 为该扣款生成 invoice
  3. 使用新的支付方式处理支付
  4. 支付成功后,将订阅重新激活为 active 状态
1

Handle subscription.on_hold webhook

收到 subscription.on_hold webhook 后,更新应用状态并通知客户:
2

Update payment method

客户准备好更新支付方式后,调用 Update Payment Method API:
如果客户已保存支付方式,您也可以使用现有的支付方式 ID:
3

Monitor webhook events

更新支付方式后,监控以下 webhook 事件:
  1. payment.succeeded - 剩余应付款的扣款成功
  2. subscription.active - 订阅已重新激活

订阅事件 Payload 示例


更改订阅计划

您可以使用 change plan API endpoint 升级或降级订阅计划。这允许您修改订阅的产品、数量并处理按比例计费。

Change Plan API Reference

有关更改订阅计划的详细信息,请参阅我们的 Change Plan API 文档。

按比例计费选项

更改订阅计划时,您有四种方式处理立即扣款:

1. prorated_immediately

  • 按剩余时间对当前计费周期的未使用部分进行抵扣。抵扣金额涵盖基础计划、数量和任何附加项
  • 然后按新计划、数量和附加项收取一个完整周期的费用。该扣款本身不会按比例计算
  • 立即净扣款 =(新的完整周期)减去(剩余比例 × 旧的完整周期)。如果抵扣金额更大,差额会作为订阅范围的 credit 留作未来续订使用
  • 在试用期内,这会立即将用户切换到新计划,并立即向客户收费

2. full_immediately

  • 按新计划的完整订阅金额向客户收费,不抵扣之前的周期
  • 无论升级还是降级,客户都需要从头支付整个新计划价格
  • 当您希望无论旧计划剩余多长时间都收取全额时,此选项非常有用

3. difference_immediately

  • 客户只需支付旧计划价格与新计划价格之间的差额
  • 金额不取决于周期内何时进行变更。在第 1 天和第 29 天进行相同升级,费用相同
  • 升级时,客户会立即支付差额。例如,$30/月 → $80/月 = 立即收取 $50
  • 降级时,价格差额会存储为订阅范围的 credit,并自动应用于未来续订。例如,$50/月 → $20/月 = 存储 $30 credit

4. do_not_bill

  • 立即应用计划变更,但不会在变更时收费。新计划、数量和附加项可立即使用
  • 由于现在不会收费,升级会让客户在当前周期剩余时间内免费享受更高等级计划。降级会立即生效,但不会抵扣客户已支付周期中未使用的部分
  • 通过 do_not_bill 授予的附加项不会在后续计划变更时抵扣,因为这些附加项从未计费。后续变更会按新的附加项数量全额计费
  • 更新后的计划(以及数量/附加项)会在下一次计划续订时计费,并且会保留原始计费日期
全部三种“立即收费”模式都会重置计费周期。 prorated_immediately、difference_immediately 和 full_immediately 会将订阅的 next_billing_date 移至变更日期。只有 do_not_bill 会保留原始续订日期,但不会立即收费。

行为

  • 调用此 API 后,Dodo Payments 会根据您选择的按比例计费选项立即发起扣款
  • 使用 prorated_immediately 时,每次变更都会计算当前周期未使用部分的抵扣金额,无论升级还是降级均如此。如果抵扣金额超过新周期扣款,剩余金额会添加到订阅的 credit balance 中。这些 credit 专属于该订阅,只会用于抵扣同一订阅未来的周期性付款
  • 使用 difference_immediately 时,净额始终是确切的价格差额。对于降级,超出的金额会存储为订阅范围的 credit,与 prorated_immediately 相同
  • full_immediately 选项会跳过 credit 计算,并收取完整的新计划金额
  • do_not_bill 选项会立即应用变更,但将计费推迟到下一次续订日期,并保留该日期
选择按比例计费模式:
  • difference_immediately — 客户支付价格差额。最可预测的选项;无论在周期内何时变更,扣款都相同。
  • prorated_immediately — 仅按当前周期的未使用时间向客户提供 credit。扣款金额会根据变更发生的时间而变化。
  • full_immediately — 客户支付完整的新计划金额。不抵扣之前的周期。
  • do_not_bill — 现在不收费。新计划会在下一次续订时计费。唯一保留原始计费日期的模式。

扣款处理

  • 计划变更时发起的立即扣款通常会在 2 分钟内完成处理
  • 如果立即扣款因任何原因失败,订阅会自动暂停,直到问题解决

按需订阅

按需订阅让您可以灵活地向客户收费,而不只是按照固定计划收费。所有账户均可使用此功能。
创建按需订阅: 要创建按需订阅,请使用 POST /checkouts API endpoint,并在 request body 中包含 subscription_data.on_demand 字段。这样可以在不立即收费的情况下授权支付方式,或设置自定义初始价格。
POST /subscriptions 已弃用。现有集成仍可使用,但新集成应通过包含 subscription_data.on_demand 的 Checkout Session(POST /checkouts)创建按需订阅。有关当前流程,请参阅 On-Demand Subscriptions Guide。
向按需订阅收费: 对于后续扣款,请使用 POST /subscriptions//charge endpoint,并指定此次交易向客户收取的金额。
有关完整的分步指南(包括 request/response 示例、安全的重试策略和 webhook 处理),请参阅 On-Demand Subscriptions Guide。

关于订阅计费的关键事项

将订阅期限设置得长于支付频率。 如果订阅期限等于支付频率(例如 period = 1 month、frequency = 1 month),订阅将仅对单个周期有效,随后进入 expired,而不是续订。对于持续的月度计划,请设置较长的订阅期限(例如 20 年),并使用月度支付频率。
货币会在首次成功扣款时锁定。 创建 checkout 时始终明确传递 billing_currency 和 billing_address.country。如果省略,系统会根据客户 IP 检测货币(Adaptive Currency);订阅首次扣款后,货币将在其整个生命周期内固定。客户之后旅行也无法切换货币。
试用期会进行 $0 授权,而不是扣款。 订阅包含试用期时,试用期开始会创建一次 $0 mandate 授权以保存卡片;首次实际扣款会在试用期结束时进行。在 payments list 中,免费试用中的订阅恰好显示一笔金额为 0 的支付,其 total_amount 为 0。付费试用则会提前收取其 trial_amount。
订阅生命周期: past_due = 续订失败且宽限期正在运行(客户保留访问权限)。on_hold = 续订失败(可恢复:提示客户更新支付方式;适用 dunning 重试)。expired = 期限结束且未续订,无法重新激活。客户必须重新订阅。cancelled = 由客户或商户结束。大多数续订失败是发卡方拒绝(余额不足、卡片被拒),而不是 Dodo 错误。
印度卡使用 RBI e-mandate。 Off-session 扣款(续订和计划变更扣款)可能需要最长约 48 小时才能结算,并且超过 ₹15,000 的周期性自动扣款需要客户重新进行身份验证(因此超过该限额的升级无法使用现有 mandate)。当一笔扣款仍处于 processing 状态时,同一订阅上的第二笔扣款会失败,并显示 “Cannot create new charge as previous payment is not successful yet.” 非印度卡会接近即时确认。
订阅在 USD 中的最低金额为 $1.00。 Checkout 会使用 TOTAL_PAYMENT_AMOUNT_BELOW_MINIMUM_AMOUNT 拒绝低于此总额的支付。除 USD、EUR 和 GBP 外的货币也必须至少价值 $1.00;请参阅 Minimum Amounts。低于最小货币单位中的 100 的按需扣款 product_price 会被 product_price: value out of range 拒绝。价格恰好为 $0 的订阅产品是允许的;请参阅 Card-Optional at Zero Price。如需在不收费的情况下授权卡片,请使用按需 mandate_only setup。

相关 API 参考

Create Subscription (Deprecated)

用于直接创建订阅的 Legacy API。新集成请使用 Checkout Sessions

Change Subscription Plan

使用按比例计费选项升级、降级或更改订阅计划的 API 参考

Update Payment Method

更新支付方式并重新激活暂停订阅的 API 参考

Patch Subscription

更新订阅详情和配置的 API 参考
最后修改于 2026年10月8日