Skip to main content

概述

Dodo Payments API 使用标准 HTTP 状态代码和自定义错误代码来指示 API 请求的成功或失败。当发生错误时,API 会返回适当的 HTTP 状态代码和包含错误详细信息的 JSON 响应。 每个错误响应包括:
  • 指示错误一般类别的 HTTP 状态代码
  • 识别错误确切性质的特定错误代码
  • 解释出错原因的人类可读错误消息
  • 适用时关于错误的附加详细信息
理解这些错误代码及其含义对于以下方面至关重要:
  • 调试集成问题
  • 在您的应用程序中实现适当的错误处理
  • 向最终用户提供有意义的反馈
  • 维护强大的支付处理系统
这是 API 和业务逻辑 错误。对于失败支付时返回的 卡拒绝原因(如 INSUFFICIENT_FUNDSCARD_DECLINED),请参阅 交易失败 参考。

标准 API 错误代码

错误响应格式

当发生错误时,API 返回具有以下结构的 JSON 响应:

错误代码参考

下面的错误代码按与 API 的相关领域分组。每个条目列出了触发条件和 API 返回的消息。

认证与账户

  • UNAUTHORIZED
    • 触发条件: 无 API 密钥或无效令牌/范围
    • 消息: 您无权限执行此操作
  • MERCHANT_NOT_LIVE
    • 触发条件: 商家仍处于测试模式
    • 消息: Merchant 尚未上线
  • BUSINESS_ARCHIVED
    • Trigger: 对已归档企业发起任何面向客户的请求(checkout、payment link、storefront、Customer Portal 或 license key)
    • Message: 此企业已归档,不再接受请求

Payments & Checkout

  • CHECKOUT_SESSION_CONSUMED
    • Trigger: Checkout session 已生成 payment
    • Message: Checkout session 已被使用
  • NO_ELIGIBLE_PAYMENT_METHODS
    • Trigger: 过滤后没有剩余内容
    • Message: 未找到符合条件的 payment methods
  • PAYMENT_NOT_SUCCEEDED
    • Trigger: 尝试对未成功的 payment 进行 refund/process
    • Message: 提供的 payment 尚未成功
  • PREVIOUS_PAYMENT_PENDING
    • Trigger: 在上一个 payment 处于非终止状态时尝试创建 charge
    • Message: 上一个 payment 尚未成功,无法创建新的 charge
  • UNSUCCESSFUL_PAYMENT_ID
    • Trigger: Payment ID 引用未成功的 payment
    • Message: Payment ID 的状态未成功。

Connectors & BYOP

这些错误与商户自有的 payment connectors(Bring Your Own Processor)相关。
  • BYOP_CONNECTOR_DISABLED
    • Trigger: 更新通过已禁用 BYOP connector 路由的 subscription 上的 payment method
    • Message: 此 subscription 通过商户自有的(BYOP)connector 路由,而该 connector 当前已禁用
  • BYOP_CUSTOM_INVOICE_ADDRESS_MISSING
    • Trigger: 商户路由的(BYOP)payment 缺少必需的 custom invoice address
    • Message: payment 通过商户的 connector 路由时,必须提供 BYOP custom invoice address
  • CONNECTOR_LABEL_ALREADY_EXISTS
    • Trigger: 创建 label 已存在的 connector
    • Message: 此 label 的 connector 已存在。请选择其他 label。

Refunds

  • EXISTING_REFUND_REQUEST_PROCESSING
    • Trigger: 上一个 refund request 仍在处理中
    • Message: 状态为 “Pending” 的 refund request 仍在处理中
  • LINE_ITEM_FULLY_REFUNDED
    • Trigger: 尝试对已完全退款的 line item 进行 refund
    • Message: Line item 已完全退款,无法继续退款。
  • LINE_ITEM_NOT_FOUND
    • Trigger: Item ID 不属于所引用的 payment
    • Message: 在 payment 中未找到 line item
  • LINE_ITEM_PRORATED
    • Trigger: 尝试对按比例计算的 line 进行 refund 或 update
    • Message: Line item 无法退款,因为它是按比例计算的
  • LINE_ITEM_REFUND_AMOUNT_TOO_HIGH
    • Trigger: Refund amount > paid amount(含 tax)
    • Message: Line item 请求的含 tax refund amount 为 ,高于 paid amount
  • LINE_ITEM_REFUND_AMOUNT_TOO_LOW
    • Trigger: Refund amount 低于 minimum threshold
    • Message: Line item 请求的 refund amount 为 ,金额过低
  • NOTHING_TO_REFUND
    • Trigger: 没有剩余可退款金额;所有正数 line items 均已完全退款
    • Message: 没有剩余可退款金额。所有正数 line items 均已完全退款。
  • PARTIAL_REFUND_NOT_ALLOWED
    • Trigger: 尝试对仅支持全额退款的 payment method 进行 partial refund
    • Message: 此 payment method 不允许 partial refunds
  • PAYMENT_ALREADY_REFUNDED
    • Trigger: 重复 refund
    • Message: 此 payment 已退款
  • PAYMENT_HAS_BEEN_REFUNDED
    • Trigger: Payment 已完全退款
    • Message: Payment ID 已完全退款。
  • REFUND_AMOUNT_EXCEEDS_PAID_AMOUNT
    • Trigger: Aggregate refund amount > paid amount
    • Message: 计算出的 refund amount 大于 paid amount
  • REFUND_WINDOW_EXPIRED
    • Trigger: 超出允许的 refund window
    • Message: Payment 创建 天后无法发起 refunds。请联系 support@dodopayments.com
  • ZERO_AMOUNT_PAYMENT_REFUND_NOT_ALLOWED
    • Trigger: 尝试对零金额 payment 进行 refund
    • Message: 无法对 currency amount 为零的 payment 进行退款

Subscriptions & Add-ons

  • ADDONS_IN_USAGE_BASED_BILLING_NOT_SUPPORTED
    • Trigger: 尝试向 usage-based billing subscriptions 添加 addons
    • Message: Usage Based Billing 不支持 Subscriptions 中的 addons
  • ADDONS_NOT_ALLOWED_FOR_ON_DEMAND
    • Trigger: 尝试向 on-demand subscriptions 添加 addons
    • Message: on demand subscriptions 不允许使用 addons
  • CANCEL_SCHEDULED_PLAN_CHANGE_FOR_CUSTOMER_PORTAL_DISABLED
    • Trigger: Customer Portal 尝试取消 scheduled plan change,但企业已禁用此操作
    • Message: customer portal 已禁用取消 scheduled plan change。
  • CHARGE_NOT_ALLOWED_FOR_SCHEDULED_CANCELLATION
    • Trigger: 尝试对计划取消的 subscription 收取费用
    • Message: Subscription 已计划取消
  • CUSTOMER_HAS_EXISTING_SUBSCRIPTION
    • Trigger: 为已有 subscription 的 customer 创建 subscription,且不允许每位 customer 拥有多个 subscriptions
    • Message: Customer 已有 subscription。若要允许每位 customer 拥有多个 subscriptions,请更改 business settings
  • DO_NOT_BILL_NOT_ALLOWED_IN_CUSTOMER_PORTAL
    • Trigger: Customer Portal plan change 使用 do_not_bill proration mode
    • Message: customer portal 不允许使用 do_not_bill proration mode
  • DUPLICATE_ADDON_IDS_IN_REQUEST
    • Trigger: 同一个 addon_id 在 request 中出现多次
    • Message: 不允许重复的 addon IDs
  • INACTIVE_SUBSCRIPTION_PLAN_CHANGE_NOT_SUPPORTED
    • Trigger: 对 inactive subscription 执行 plan change
    • Message: 不支持对 inactive subscriptions 更改 plans
  • INVALID_PRORATION_MODE_WITH_NEXT_BILLING_DATE
    • Trigger: 将不同于 full_immediately 的 proration mode 与 effective_at: next_billing_date 一起使用
    • Message: effective_at: next_billing_date 仅允许使用 full_immediately proration mode
  • MISSING_ADDON_IDS
    • Trigger: addon_id list 为空或包含未知 IDs
    • Message: 一个或多个 product IDs 不存在:
  • ON_DEMAND_PLAN_CHANGE_NOT_SUPPORTED
    • Trigger: on-demand 不允许 plan swap
    • Message: 不支持对 on demand subscriptions 更改 plans
  • ON_DEMAND_USAGE_BASED_BILLING_NOT_SUPPORTED
    • Trigger: 尝试将 on-demand 用于 usage-based billing
    • Message: Usage Based Billing 不支持 On Demand Subscriptions
  • ONE_TIME_PRODUCTS_NOT_ALLOWED_FOR_ON_DEMAND
    • Trigger: 向 on-demand subscription 添加 one-time product
    • Message: on demand subscriptions 不允许使用 one-time products
  • PENDING_PLAN_CHANGE_EXISTS
    • Trigger: 上一个 plan change 仍在等待 payment 时请求新的 plan change
    • Message: 此 subscription 已存在 pending plan change。请等待当前 payment 完成。
  • PLAN_CHANGE_FOR_CUSTOMER_PORTAL_DISABLED
    • Trigger: 通过 Customer Portal 执行 plan change,但企业已禁用此功能
    • Message: customer portal 的 Subscription plan change 已禁用。
  • PLAN_CHANGE_NOT_ALLOWED_FOR_SCHEDULED_CANCELLATION
    • Trigger: 尝试对计划取消的 subscription 执行 plan change
    • Message: Subscription 已计划取消
  • SCHEDULE_PLAN_CHANGE_FOR_CUSTOMER_PORTAL_DISABLED
    • Trigger: 通过 Customer Portal 安排 plan change,但企业已禁用此功能
    • Message: 此企业已禁用安排 plan changes。
  • SCHEDULED_PLAN_CHANGE_EXISTS
    • Trigger: 已存在 scheduled plan change 时创建新的 scheduled plan change
    • Message: 此 subscription 已存在 scheduled plan change。创建新的变更前,请先取消现有的 scheduled change。
  • SCHEDULED_PLAN_CHANGE_NOT_FOUND
    • Trigger: 引用或取消不存在的 scheduled plan change
    • Message: 未找到此 subscription 的 scheduled plan change。
  • SUBSCRIPTION_EXPIRED
    • Trigger: Billing past expires_at
    • Message: Subscription 已过期,无法创建新的 charges
  • SUBSCRIPTION_INACTIVE
    • Trigger: Status ≠ active
    • Message: Subscription 未激活
  • SUBSCRIPTION_NOT_ON_DEMAND
    • Trigger: 预期为 on-demand,但得到的是 fixed interval
    • Message: Subscription 已不是 on demand
  • SUBSCRIPTION_PAYMENT_RETRY_LIMIT_EXCEEDED
    • Trigger: Subscription payment retries 超过最大尝试次数
    • Message: 此 subscription 已超过 10 次的最大 retry limit

Products, Cart & Brands

  • BRAND_ALREADY_ARCHIVED
    • Trigger: 归档已经归档的 brand
    • Message: Brand 已归档
  • BRAND_ARCHIVED
    • Trigger: 更新已归档的 brand、提交其进行 verification,或向其标记新的 product、product collection 或 subscription
    • Message: Brand 已归档,无法更新
  • BRAND_ARCHIVE_TARGET_REQUIRED
    • Trigger: 归档仍包含 products、live subscriptions 或 product collections 且没有 move_products_to target 的 brand
    • Message: Brand 有 12 个 product(s)。请将 move_products_to 设置为 target brand,以便重新标记它们。
  • BRAND_MISMATCH
    • Trigger: Cart items 属于不同的 brands
    • Message: Product cart 中的所有 items 应属于同一 brand
  • BRAND_NOT_ENABLED
    • Trigger: Brand 已禁用或未激活
    • Message: 提供的 brand 未启用
  • BRAND_SUBMISSION_NOT_ENABLED
    • Trigger: Brand verification resubmission 功能未启用
    • Message: Brand verificatin resubmission 未启用
  • CANNOT_ARCHIVE_PRIMARY_BRAND
    • Trigger: 归档 primary brand,其 brand ID 即 business ID
    • Message: Primary brand 无法归档
  • FILE_IN_USE
    • Trigger: 删除仍被 active entitlement grants 引用的 digital product file
    • Message: Digital file 仍被 active grants 引用
  • INVALID_BRAND_ARCHIVE_TARGET
    • Trigger: move_products_to 指定正在归档的 brand、已归档的 brand 或其他 business 的 brand
    • Message: move_products_to 必须是此 business 中未归档的 brand
  • INVALID_SUGGESTED_PRICE
    • Trigger: PWYW price < minimum allowed price
    • Message: Suggested Price 不能低于 minimum price。对于 pay what you want,price 被视为 minimum accepted amount
  • LOCALIZED_PRICE_ALREADY_EXISTS
    • Trigger: 此 product 和 country/currency 已存在 localized price
    • Message: 此 product 和 country/currency 已存在 localized price
  • LOCALIZED_PRICE_DUPLICATES_BASE
    • Trigger: Localized price 与 product 的 base currency/country 重复
    • Message: Localized price 与 product 的 base currency/country 重复
  • LOCALIZED_PRICE_SHAPE_MISMATCH
    • Trigger: Localized price shape 与 product 的 pricing_mode 不匹配
    • Message: Localized price shape 与 product 的 pricing_mode 不匹配
  • MISSING_PRODUCT_INFORMATION
    • Trigger: Product 存在但缺少必需信息
    • Message: Product 存在,但其他必需信息缺失或无效
  • PAY_AS_YOU_WANT_AMOUNT_REQUIRED
    • Trigger: PWYW product 缺少 price
    • Message: pay as you want product 必须提供 Amount
  • PRODUCT_CART_EMTPY
    • Trigger: 提交空的 product cart
    • Message: product_cart 为空(错误代码特意拼写为 EMTPY,以匹配 API 返回的确切值)
  • PRODUCT_COLLECTION_IS_DELETED
    • Trigger: 操作已删除的 product collection
    • Message: 无消息
  • PRODUCT_COLLECTION_MUST_HAVE_PRODUCTS
    • Trigger: 从 collection 中移除最后一个 product(或最后一个包含 products 的 group)
    • Message: 无法删除 collection 中的最后一个 product。请改为归档 collection。
  • PRODUCT_IS_DELETED
    • Trigger: Product 已软删除
    • Message: 无消息
  • PRODUCT_PRICING_MODE_REQUIRED
    • Trigger: 在 product 的 pricing_mode 设置前添加 localized prices
    • Message: 添加 localized prices 前必须设置 product pricing_mode
  • SLUG_ALREADY_TAKEN
    • Trigger: 请求的 product slug / short URL 已被使用
    • Message: Slug 已被占用
  • UNABLE_TO_EDIT_PRIMARY_BRAND
    • Trigger: 尝试通过常规 API 更新 primary brand
    • Message: 无法通过此 API endpoint 更新 primary brand。

Discounts

  • DISCOUNT_ALREADY_USED_ON_SUBSCRIPTION
    • Trigger: 重新应用已在此 subscription 上使用过的 discount
    • Message: 此 discount 已在此 subscription 上使用过
  • DISCOUNT_CODE_ALREADY_EXISTS
    • Trigger: 创建重复的 discount code
    • Message: Discount Code 已存在
  • DISCOUNT_CODE_EXPIRED
    • Trigger: Discount code 已超过其 expires_at date
    • Message: Discount code 已过期
  • DISCOUNT_CODE_USAGE_LIMIT_EXCEEDED
    • Trigger: 达到 usage_limit 后重复使用 discount
    • Message: Usage limit 不能小于 times_used / Discount code 已达到 usage limit
    • Note: 终止状态——该 code 已耗尽。请勿重试。
  • DISCOUNT_CONCURRENT_REDEMPTION
    • Trigger: 同一 code 的另一次 redemption 持有 usage-limit row lock 的时间过长
    • Message: Discount 正在并发兑换;请重试
    • Note: 临时错误。该 code 可能仍有可用额度,因此可以安全重试。不要向 customer 显示“code 已耗尽”。
  • DISCOUNT_CURRENCY_OPTION_INVALID
    • Trigger: create 或 update 时使用无效的 currency_options
    • Message: Flat discount 至少需要一个具有可解析 default 的 currency option / 不允许重复的 currency options / 最多只能将一个 currency option 标记为 default
  • DISCOUNT_CUSTOMER_NOT_ELIGIBLE
    • Trigger: Customer 不满足 code 的 customer_eligibilityfirst_timeexisting,或不在 specific code 的 allow list 中)
    • Message: Customer 不符合此 discount code 的条件
  • DISCOUNT_MINIMUM_SUBTOTAL_NOT_MET
    • Trigger: Cart subtotal 低于为 checkout currency 配置的 minimum_subtotal
    • Message: Cart subtotal 低于 discount 要求的 minimum required subtotal
  • DISCOUNT_NOT_YET_ACTIVE
    • Trigger:starts_at date 前使用 code
    • Message: Discount code 尚未激活(starts_at 位于未来)
  • DISCOUNT_PER_CUSTOMER_USAGE_LIMIT_EXCEEDED
    • Trigger: Customer 已兑换 code per_customer_usage_limit
    • Message: 此 discount code 已超过每位 customer 的 usage limit
  • DISCOUNT_NOT_APPLICABLE_TO_NEW_PRODUCT
    • Trigger: 将 plan change 到现有 discount 不适用的 product
    • Message: Discount 不适用于新 plan 的 product
  • DISCOUNT_NOT_AVAILABLE_FOR_ON_DEMAND
    • Trigger: 将 code 应用于 on-demand subscription
    • Message: Discount coupon 不适用于 on demand subscriptions
  • DISCOUNT_NOT_AVAILABLE_FOR_PRODUCT
    • Trigger: 将 code 应用于无关的 product(s)
    • Message: Discount coupon 不适用于此 product
  • INVALID_DISCOUNT_CODE
    • Trigger: Code 不存在或不适用
    • Message: Invalid Discount Code / Discount Code 无法应用于 cart 中的任何 product
  • INVALID_PERCENTAGE
    • Trigger: Percent amount > 100%(或 10,000 basis points)
    • Message: Percentage amount 不能超过 10000 / Discount code amount 不能超过 100%
  • UNSUPPORTED_DISCOUNT_TYPE
    • Trigger: 使用不受支持的 discount type。percentageflat 均受支持;不支持 per-unit amount discounts。
    • Message: 仅支持 percentage 和 flat discount codes

License Keys

  • ACTIVATION_LIMIT_LESS_THAN_CURRENT_AMOUNT
    • Trigger: License-key activations:new limit < existing instance count
    • Message: New activation limit 不能小于 current instances count
  • INACTIVE_LICENSE_KEY
    • Trigger: Key status ≠ active
    • Message: License key 未激活
  • LICENSE_KEY_LIMIT_REACHED
    • Trigger: Activations = limit
    • Message: 已达到 license key activation limit
  • LICENSE_KEY_NOT_FOUND
    • Trigger: Instance ID 或 key ID 无效
    • Message: 未找到 license key instance,或其不属于此 license key
  • NO_EXPIRY_ON_SUBSCRIPTION_LICENSE_KEYS
    • Trigger: 尝试为 sub-based key 设置 expiry
    • Message: 无法为 subscription-based license key 设置 expiry date

Usage-Based Billing & Meters

  • DUPLICATE_METER_IDS_IN_REQUEST
    • Trigger: 同一 meter ID 在 request 中出现多次
    • Message: 不允许重复的 Meter Ids
  • INVALID_QUANTITY
    • Trigger: 为 usage-based pricing 指定无效 quantity
    • Message: Usage based price products 仅允许 1 个 quantity
  • METER_IS_DELETED
    • Trigger: 尝试使用已删除的 meter
    • Message: Meter 已被删除
  • MISSING_METER_IDS
    • Trigger: Meter ID list 为空或包含无效 IDs
    • Message: 一个或多个 meter IDs 不存在:

Credit-Based Billing

  • CREDIT_ENTITLEMENT_IS_DELETED
    • Trigger: 操作已删除的 credit entitlement
    • Message: Credit entitlement 已被删除
  • CREDIT_ENTITLEMENT_NAME_ALREADY_EXISTS
    • Trigger: 创建 name 已存在的 credit entitlement
    • Message: 此 name 的 credit entitlement 已存在
  • OVERAGE_LIMIT_EXCEEDED
    • Trigger: usage 或 credit deduction 将超过配置的 overage limit
    • Message: 已超过 overage limit

Wallet

  • INSUFFICIENT_WALLET_FUNDS
    • Trigger: Wallet balance < debit amount
    • Message: Wallet 中的资金不足
  • NEGATIVE_BALANCE_ADJUSTMENT
    • Trigger: 尝试使 wallet balance 变为负数
    • Message: 不允许将 wallet balance 变为负数

Currency, Tax & Region

  • EXCHANGE_RATE_NOT_FOUND
    • Trigger: from → to currency pair 没有 FX rate
    • Message: 未找到将 Currency 转换为 Currency 的 exchange rate
  • INVALID_TAX_ID
    • Trigger: VAT/GST/TIN validation 失败
    • Message: Tax Id 无效
  • REQUEST_AMOUNT_BELOW_MINIMUM
    • Trigger: Amount < product minimum
    • Message: Amount 不能低于 product 指定的 minimum amount
  • TOTAL_PAYMENT_AMOUNT_BELOW_MINIMUM_AMOUNT
    • Trigger: Combined cart total < gateway minimum
    • Message: 处理 payment 至少需要
  • UNSUPPORTED_BILLING_CURRENCY
    • Trigger: 此 subscription 不支持请求的 billing currency
    • Message: Subscriptions 不支持非 USD billing currency
  • UNSUPPORTED_COUNTRY
    • Trigger: Geo 尚不受支持
    • Message: 当前不支持 Country
  • UNSUPPORTED_CURRENCY
    • Trigger: Product 或 addon currency 不是 Dodo Payments 可收取费用的 currency。Base prices 可使用任何可收取费用的 currency 设置,因此这通常意味着 currency code 无效或尚不受支持。
    • Message: Currency 当前不受支持 / 当前仅支持 USD 和 INR products / Addon price 当前仅支持 USD 和 INR / billing_currency 只能请求 USD 或 INR / Currency Not Supported / Unexpected currency for Indian card subscriptions
  • UNSUPPORTED_TAX_CATEGORY
    • Trigger: Tax category string 不在 enum 中
    • Message: 当前不支持 Category

Validation & Requests

  • DUPLICATE_LINE_ITEMS_IN_REQUEST
    • Trigger: 同一个 item_iditems[] 中出现两次
    • Message: items array 中指定了重复的 item_ids
  • INVALID_QUERY_PARAMS
    • Trigger: 互斥或格式错误的 query parameters
    • Message: Query params 只能包含 time_frame 或 (start, end) 其中之一
  • INVALID_REQUEST_BODY
    • Trigger: JSON 格式错误或违反 schema
    • Message: Request body 无效。请检查 request headers 和 object。
  • INVALID_REQUEST_PARAMETERS
    • Trigger: Semantics 错误(例如 date 已在过去)
    • Message: 无法将 next_billing_date 更改为过去的时间
  • MAXIMUM_KEYS_REACHED
    • Trigger: Metadata / custom-fields 超过 50 个 pairs
    • Message: 超过 50 个 key-value pairs

General & System

  • INTEGER_CONVERSION_FAILURE
    • Trigger: server-side 任何 integer ↔ string/decimal conversion 失败
    • Message: Integer Conversion Failure
  • INTERNAL_SERVER_ERROR
    • Trigger: 未捕获的 exceptions;应在 server-side 记录详细信息
    • Message: 无 public message(generic 500)
  • NOT_FOUND
    • Trigger: 任何缺失 resource 的通用 404
    • Message: 未找到 Item (或更具体的消息)
  • TOO_MANY_REQUESTS
    • Trigger: 429 rate-limit
    • Message: 无消息
  • UNSUPPORTED_ACTION
    • Trigger: Resource type 不支持的 action
    • Message: 不支持对 usage based subscriptions 更改 plans

Best Practices

  1. 始终在 application 中优雅地处理 errors
  2. 实现适当的 error logging
  3. 为最终用户使用合适的 error messages
  4. 为 transient errors 实现 retry logic
  5. 对于未解决的问题,请联系 support

Support

如需进一步了解 error codes 或 integration issues,请通过 support@dodopayments.com 联系我们的 support team。
最后修改于 2026年8月21日