Skip to Content
🔑 开发者平台通用商户收款

通用商户收款

外部系统已有自己的订单、订阅和交付时,可由商户服务端按金额创建 TDCloud 收款单,再让买家跳转收银台。无需预先创建 TDCloud 商品;TDCloud 确认收款和结算,商户系统自行更新业务订单与权益。

1. 准备商户服务端凭据

在 开放平台 → 应用资料 选择“自己的后端服务器(机密客户端)”,勾选 merchant_payments.create(创建商户收款单)和 merchant_payments.read(查询商户收款结果),提交申请或变更审核。账号须拥有已启用商户,平台自动绑定该商户。

已有应用无需重建:在原应用资料中添加权限,点击 提交变更审核;审核期间原配置继续生效。管理员可在 准入审核 → 应用审核 审核申请,或对已签发客户端通过 调整权限 补批,填写审核说明。权限不会自动开通;公共客户端须先提交机密客户端类型变更,不能直接补批这两个权限。

获批后查看应用接入配置中的已批准权限,重新获取包含这两个权限的 Client Credentials 令牌;旧令牌不会自动获得新增权限。不要改用商品订单支付的 payments.create、payments.read。所有本页 OpenAPI 只接受 client_credentials 令牌,不接受用户授权令牌;调用方不提交买家编号或商户编号。

服务地址使用开发者中心分配的完整地址,见 接入概览。Secret 和 Access Token 仅保存在商户服务端。

curl -X POST "{TOKEN_ENDPOINT}" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id={CLIENT_ID}" \ --data-urlencode "client_secret={CLIENT_SECRET}" \ --data-urlencode "scope=merchant_payments.create merchant_payments.read"

使用响应的 access_token 和实际 scope,按 expires_in 管理有效期。Client Credentials 不签发用户 Refresh Token,过期后用服务端凭据重新获取令牌。公共客户端或未绑定商户的客户端不能使用此流程。

2. 支付流程与方式选择

商户服务端提交订单金额和币种,TDCloud 负责金额校验、可用支付方式、渠道适配及结算。默认无需查询或传入渠道编号;买家进入返回的收银台后选择支付方式。订单计价币种由 currency 指定,实际付款方式和钱包结算由平台处理。

可选:限定单一渠道

需要限定支付方式的现有接入可使用以下渠道目录,再传入 payment_no。渠道目录的 currency 是渠道默认展示币种,不是收款订单的金额精度来源;不要据此换算订单金额。

GET {API_BASE_URL}/openapi/v1/merchant-payment-channels

权限:merchant_payments.read。HTTP 200 返回 {"items": [...]};无可用渠道时数组为空。

curl "{API_BASE_URL}/openapi/v1/merchant-payment-channels" \ -H "Authorization: Bearer {ACCESS_TOKEN}"
字段类型说明
payment_nostring建单时使用的真实渠道编号,不是显示名称
namestring渠道名称
providerstring当前支持 stripe、dog-coin(TDC)
ownerstringplatform 或 merchant
currencystring渠道支付币种
login_requiredboolean渠道本身是否必须登录;商户禁止未登录消费时,收银台也会要求登录
test_modeboolean是否使用管理员分配的 Stripe 测试渠道

可用渠道受商户归属、启用状态和调试授权约束。首期支持 TDC 与已配置签名 Webhook 的 Stripe。TDC 始终要求买家登录 TDCloud;其他渠道是否允许未登录消费由商户设置。不要将本目录套用于商品订单的渠道发现或报价。

3. 创建收款单

POST {API_BASE_URL}/openapi/v1/merchant-payments

权限:merchant_payments.create。请求头:Authorization: Bearer {ACCESS_TOKEN}、Content-Type: application/json。

参数类型必填约束
external_referencestring是商户业务订单引用,去除首尾空白后非空,最长 191 字节;创建后固定
idempotency_keystring是同一次建单的重试键,最长 128 字节;同商户内唯一
amountstring是,新接入使用正数十进制金额字符串,例如 "10.50";由平台校验币种精度并转换,规则见下方
currencystring是平台已开放的订单计价币种,使用大写代码;可用付款方式由平台决定
payment_nostring否传入时限定为该渠道;省略或为空时由买家在收银台选择可用支付方式
descriptionstring否展示给买家的付款内容,最长 500 字节,去除首尾空白;不要放入内部编号、密钥或其他敏感信息
expires_ininteger否支付有效秒数,60~7200;默认 1800(30 分钟),建单后固定
notify_enabledboolean否省略时使用显式通知参数或商户默认配置;false 关闭本单通知,不能同时传通知地址/密钥;true 要求存在有效通知配置
notify_urlstring否服务端通知的公网 HTTPS 地址,须与 notify_secret 同时传入;见状态通知一节
notify_secretstring否独立随机签名密钥,32~256 字节,不含空白
return_urlstring否支付确认后返回的完整 HTTPS 地址,最长 2048 字节;规则见下一节

可选字段可直接省略,也可用 null 表示未填写。description、payment_no、return_url 去除首尾空白后为空时,按未填写处理。expires_in: 0 是无效有效期;notify_enabled: false 则明确关闭本单通知。通知地址和签名密钥仍须成对提供,密钥不能包含空白字符。

金额示例

提交十进制字符串 amount,不需要在商户侧读取币种精度或换算最小单位。TDCloud 按平台币种规则精确校验和转换,不会四舍五入超出精度的金额。

订单金额请求 currency请求 amount响应 amount
10.50 USDUSD"10.50""10.50"
10.50 TDCTDC"10.50""10.50000000"
100 JPY(币种已开放时)JPY"100""100"
  • amount 必须是 JSON 字符串,最长 64 字节,仅允许数字和一个小数点;不接受正负号、空白、逗号、货币符号、科学计数法、.5 或 1.。零和负金额不能建单。
  • 非零小数位不能超出平台对该币种的精度。例如 USD "10.001"、JPY "100.5" 会被拒绝。多余的末尾零可省略:"10.5"、"10.50"、"10.5000" 表示同一金额。
  • 平台校验可表示的金额范围、币种是否开放和可用支付方式;结果分别以 invalid_amount、invalid_amount_precision、currency_unavailable 或 channel_unavailable 拒绝,不会自动换币种或改金额。
  • 创建、查单、列表和新生成的状态通知都返回规范化的 amount 字符串,保留订单保存的币种精度。按十进制数核对 amount 与 currency,无需按字符串长度判断金额是否相等,也不要用浮点数或实时汇率改写历史订单。

旧接口兼容

历史接入仍可仅提交正整数 amount_minor,按订单币种最小单位表示,最大 9007199254740991,并须在平台金额范围内。amount 与 amount_minor 只能提交一种;即使另一个字段是零或 null 也会拒绝。新接入使用 amount。

响应继续包含 amount_minor、currency_decimals 和实际渠道信息,供旧接入对账;它们不是新接入的前置换算要求。同一金额在两种表示方式之间重试使用相同幂等键,仍返回原单。旧通知已保存的正文不会改写,重试保持原正文;处理历史通知时可兼容原金额字段,或调用查单获取 amount。

curl -X POST "{API_BASE_URL}/openapi/v1/merchant-payments" \ -H "Authorization: Bearer {ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ --data '{"external_reference":"merchant-order-123","idempotency_key":"merchant-order-123-attempt-1","amount":"10.50","currency":"USD","description":"订单说明","expires_in":1800,"return_url":"https://merchant.example/orders/merchant-order-123?source=tdcloud#payment"}'

成功响应:HTTP 201,重复同参数请求也返回 201 和同一收款单。

{ "order_no": "MP_EXAMPLE", "external_reference": "merchant-order-123", "payment_no": "", "amount": "10.50", "amount_minor": 1050, "currency": "USD", "currency_decimals": 2, "status": "pending", "test_mode": false, "checkout_url": "https://tdcloud.cc/checkout/merchant/MP_EXAMPLE?token=CHECKOUT_TOKEN", "return_url": "https://merchant.example/orders/merchant-order-123?source=tdcloud#payment", "expires_at": "2026-10-08T14:00:00+08:00" }

示例编号、地址、时间均为占位值。保存 order_no 与业务订单的映射,将实际返回的 checkout_url 交给买家浏览器;不能把它当作已支付凭证或在日志中暴露其中的令牌。expires_at 在建单时确定,发起渠道会话、刷新页面和重试均不会延长。

买家选择支付方式

默认建单不传 payment_no,TDCloud 保存当时可用的渠道及金额、汇率、手续费规则,返回一个收银台地址。买家在收银台选择付款方式;只有一种可用方式时直接显示该方式。商户希望限定单一渠道时仍可传入 payment_no,历史固定渠道订单沿用原方式。

买家只能看到当前商户可用且符合实际付款账号授权的方式。需要登录的方式会提示登录,未登录时不能使用 TDC 余额。TDC 可按建单时保存的汇率支付其他已启用币种的订单,页面显示实际应付 TDC;金额和订单币种保持不变。自有渠道手续费在建单时检查,发起付款时再次检查并预占。

渠道明确拒绝首次创建付款页面时,平台释放预占并允许重新选择;网络超时、服务异常或已有不明结果的重试不能据此解锁,避免生成第二张可支付会话。

首次发起渠道付款后锁定方式。再次点击或刷新继续使用同一支付尝试;渠道响应不明时不能切换方式另建会话。超时不会因选择方式或刷新而延期。尚未选择时,服务端 payment_no 为空、test_mode 为 false;选择后查单反映实际渠道和测试模式,不改变原建单参数的幂等校验。

买家收银台展示商户名称、付款说明、商户订单号、收款单号、订单金额、倒计时与支付方式。使用 TDC 时另显示按下单价格折算的实际扣款和本人的可用余额;订单计价金额不会被改写。选择付款方式后先展示订单金额、支付手续费和实际支付金额;买家确认后才创建或获取付款页面,使用 TDC 余额时确认扣款。仅切换付款方式不会发起支付或锁定渠道。支付事件号、渠道交易号及商户钱包结算信息仍只用于商户服务端查单和通知。收银台使用本单专属的方式标识,不能通过提交任意渠道编号越权付款。

幂等与重试

同一商户、同一 idempotency_key、相同规范化参数返回同一单。金额按数值规范化,冗余末尾零不构成参数变化;原单重试使用原单保存的币种精度,平台币种规则或启用状态变更不会重新解释原金额。金额、币种、渠道、外部引用、描述、有效期或返回地址变化返回 HTTP 409 payment_conflict。不同商户的幂等空间隔离;external_reference 本身不是去重键。

超时后以原键和原参数重试,不能仅因没有收到响应就换键再建一张可支付单。确需新支付尝试时,先核对原单和渠道结果,避免两张单均可付款。

支付超时

  • expires_in 是从建单成功开始计算的有效秒数。省略默认 30 分钟,也可传入 60~7200 秒(1 分钟~2 小时)。显式 1800 与省略等价;同键改为其他有效期返回 409 payment_conflict。
  • 到达固定 expires_at 后禁止继续发起支付,收银台发起接口返回 410 payment_expired。同键重试仍返回原单及原期限,不能续期。新上限用于新建订单,历史订单保留原期限。服务端查询及对账仍可用。
  • 尚未发起渠道会话的单在查询、列表、收银台读取或后台巡检时转为 expired。已发起会话的单先进入 review,后台核对付款并关闭尚未支付的 Stripe 会话;确认渠道已过期后才释放预占手续费和授信,且只释放一次。
  • 异步付款未决、渠道查单/关单失败或会话创建响应不明继续保留 review,不能直接认定失败或重复扣费。真实付款确认后,即使回调晚到,也会在钱包及账务完成后返回 paid。创建结果不明且无法获取会话号时,由 TDCloud 核对原渠道记录;确认没有发生收款后才结束为 expired,并按该单通知配置发送状态变更。
  • 后台每分钟巡检,并在渠道异常时重试。Stripe 会话自身的最短期限为 30 分钟,可能晚于收款单期限;TDCloud 会主动关单,不会用渠道期限延长收款单。不能将本地到期理解为渠道地址必定在同一瞬间关闭。Stripe 会话到期规则 、主动关闭会话 。

收银台显示倒计时,到期后移除支付入口并提示核对结果。商户遇到 review 或已付款异常时,应继续查询原单、保留稳定单号供人工对账;确认原支付尝试结束后再创建新尝试。

原收款单已确认 expired 后,可以在同一商户业务订单上使用新的 idempotency_key 创建新的收款尝试,保留原 external_reference、金额和币种。无需重新创建业务订单;旧收款单和历史支付关联应继续保留。

到期后的支付确认

expires_at 限制继续发起支付,不是拒绝接收已发生付款的截止时间。TDCloud 到期关单与渠道付款可能同时发生,异步付款也可能稍后确认。若 TDCloud 核验收款事实并完成相关账务,即使原单已返回 expired,仍可转为 paid。渠道已成功关闭的会话不能继续付款,但不能据此忽略晚到的支付结果。

  • 不要将 expired 设为禁止后续 paid 的永久终态,也不要删除原收款单与业务订单的关联。通知接收和历史查单都应允许 expired → paid。
  • 新的 paid 状态使用更高的 status_version;启用本单通知时会产生新的状态通知。未启用通知或投递失败时,可通过服务端查单和定期对账发现变化,无需无限轮询。
  • 对同一收款单,旧版本 expired 通知不能覆盖较新的 paid。status_version 仅在同一 TDCloud 收款单内比较,不能跨不同支付尝试排序。
  • 新尝试创建后,旧尝试仍需保留在对账范围。同一业务订单可能对应多个收款单;每笔真实付款按稳定支付 event_id 分别记账,但交付、订阅和权益变更还须按商户业务订单幂等。不同支付事件不代表可以交付两次。
  • 业务订单已关闭或已交付时收到另一笔确认付款,记录付款事实并进入商户的退款或人工处理流程,不可静默丢弃。TDCloud 不因业务订单关闭或晚到支付而自动退款。

4. 接入支付返回地址

return_url 由商户服务端创建收款单时设置,随后固定。首尾空白会被去除;必须是完整 HTTPS URL,不允许账号密码、反斜线或未编码空白/控制字符。未传、空字符串或历史单没有此字段时,买家留在原收银台流程。

此参数与 OAuth 的 redirect_uri 不同:无需登记为 OAuth 回调,可以按业务订单设置路径、查询参数和 # 片段。浏览器自行在收银台 URL 上添加 return_url 或 status=paid 不会覆盖保存地址或确认支付。

支付流程如下:

  1. 买家进入 TDCloud checkout_url,按商户策略登录或匿名付款。
  2. Stripe 完成或取消付款先回 TDCloud 收银台;TDC 支付也在收银台确认。
  3. 收银台向服务端查单。只有返回 paid 后才自动进入保存的 return_url,并保留“返回商户”入口。
  4. 异步付款未决时继续查单;取消支付、到期或退款/拒付不触发成功返回。浏览器取消不保证收款单立即变为终态。
  5. 商户返回页调用自己的后端,再由后端查 TDCloud 收款单,核对金额、币种和稳定 event_id,幂等更新业务订单。

原地址的路径、查询参数和片段保留;TDCloud 不自动添加 Token、单号或支付状态。商户应在原地址中携带自己的业务引用,并将回跳仅作为触发查单的入口。浏览器付款成功页、回跳参数或渠道会话创建成功都不能作为交付依据。

5. 服务端状态通知

状态通知是可选能力。默认不开启,可通过服务端查单确认结果。浏览器返回地址和服务端通知互相独立,均不必填写。

商户默认配置

在 商户中心 → 支付与结算 → 收款状态通知 配置公网 HTTPS 通知地址。保存地址后平台生成独立签名密钥,仅本次显示;将其保存到商户接收服务,完成验签后再启用默认通知。读取设置不会返回密钥,遗失时可更换。

建单方式通知行为
不传通知参数商户默认通知启用时使用默认地址与密钥,否则不发送
notify_enabled: false关闭本单通知,即使商户已启用默认通知;不要同时传地址或密钥
notify_enabled: true使用显式地址和密钥,否则使用已启用的商户默认配置;均不可用则拒绝建单
成对传 notify_url / notify_secret覆盖商户默认配置,使用本次提供的地址和密钥

生效地址与密钥在建单时固定。更改、关闭默认配置或更换密钥只影响新订单,历史订单及补发继续使用原配置;接收服务需保留旧密钥直到历史通知处理完成。相同幂等键重试不会重新读取默认配置或改变已创建订单。

单笔指定通知

建单时同时传入 notify_url 和 notify_secret,TDCloud 会向商户服务端发送 HTTPS POST。notify_url 仅允许公网 HTTPS,最长 2048 字节,不允许账号密码、片段、内网地址或重定向。notify_secret 使用商户生成的独立随机密钥,32~256 字节,不含空白;不要使用 OAuth Client Secret。地址和密钥参与建单幂等校验,创建后不能修改。

{ "external_reference": "merchant-order-123", "idempotency_key": "merchant-order-123-attempt-1", "amount": "10.50", "currency": "USD", "notify_url": "https://merchant.example/hooks/tdcloud", "notify_secret": "MERCHANT_GENERATED_RANDOM_SECRET_AT_LEAST_32_BYTES" }

商户默认通知未启用时,两个参数均省略不发送通知;已启用默认通知时,使用 notify_enabled: false 关闭本单通知。密钥不会出现在建单、查单、收银台或投递记录响应中。

通知内容与验签

每次状态变化发送 merchant_payment.status_changed,包含创建后的 pending、支付确认后的 paid、review、expired、refunded 和 chargeback。支付和账务确认、订单状态与通知事件在同一事务中保存;投递失败不撤销已确认支付。

{ "id": "MN_NOTIFICATION_EXAMPLE", "type": "merchant_payment.status_changed", "api_version": 1, "created_at": "2026-10-08T07:45:00Z", "data": { "order_no": "MP_EXAMPLE", "external_reference": "merchant-order-123", "payment_no": "CHANNEL_NO", "amount": "10.50", "amount_minor": 1050, "currency": "USD", "currency_decimals": 2, "status": "paid", "status_version": 2, "test_mode": false, "expires_at": "2026-10-08T08:00:00Z", "event_id": "MPE_PAYMENT_EXAMPLE", "provider_trade_no": "cs_EXAMPLE", "occurred_at": "2026-10-08T07:45:00Z" } }

data 是该状态发生时的收款单快照,不含收银台 Token、返回地址或通知密钥。id 是通知事件号;data.event_id 是确认支付后的稳定支付事件号,两者用途不同。created_at 是通知生成时间,支付时间使用 data.occurred_at。

请求头含义
X-TDCloud-Event-ID与请求体 id 一致的通知事件号
X-TDCloud-Timestamp本次投递的 Unix 秒时间戳
X-TDCloud-Signaturesha256= 加 HMAC-SHA256 的小写十六进制结果

签名内容为 时间戳 + "." + 原始 HTTP 请求体字节,密钥为该单创建时生效的签名密钥(商户默认密钥或显式 notify_secret)。使用常量时间比较签名,并拒绝与当前时间相差超过 5 分钟的时间戳;服务端时钟须同步。验签前不要重新序列化 JSON。例如 Python:

import hashlib import hmac import time # raw_body is the untouched HTTP request body; secret is stored server-side. timestamp = request.headers["X-TDCloud-Timestamp"] provided = request.headers["X-TDCloud-Signature"] expected = "sha256=" + hmac.new( secret.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256 ).hexdigest() if abs(time.time() - int(timestamp)) > 300 or not hmac.compare_digest(expected, provided): raise ValueError("Invalid TDCloud notification")

验签后核对订单引用、金额、币种和 test_mode,按通知 id 去重。通知可能重复或乱序;同单 status_version 单调递增,低版本不能覆盖高版本。查单也返回 status_version。支付记账继续按 data.event_id 幂等;只有 paid 表示确认支付,review 和 expired 不能作为已支付凭证。退款/拒付保留原支付事件号。

例如,同一收款单的 expired(版本 2)后可以收到 paid(版本 3);随后重投的版本 2 不得把状态改回过期。通知与查单应使用同一套支付记账和业务交付幂等处理,避免并发或补发造成重复履约。即使业务侧已将订单标为超时,较新的确认支付事实仍须记录和处理。

确认、重试与补发

商户应先可靠保存通知,再返回 HTTP 2xx;响应体不参与确认。单次投递最多等待 8 秒。超时、连接失败、3xx、4xx 和 5xx 均重试,不跟随重定向。首次异步投递后,失败间隔依次为 1 分钟、5 分钟、15 分钟、30 分钟、1 小时、2 小时、4 小时、6 小时、8 小时,共最多 10 次自动尝试。工作进程中断后可恢复;通知事件号与请求体保持一致,每次重签时间戳。

商户也可在 商户中心 → 支付与结算 → 收款通知记录 输入收款单号查看投递结果和最近明细,自动重试耗尽后点击“补发通知”。页面仅查询当前商户的订单。

方法与路径权限用途
GET /openapi/v1/merchant-payments/{order_no}/notificationsmerchant_payments.read本商户订单的投递记录,HTTP 200 返回 {"items": [...]}
POST /openapi/v1/merchant-payments/{order_no}/notifications/{event_id}/retrymerchant_payments.create将自动重试耗尽的通知重新排队,HTTP 202 返回 {"accepted": true}

记录按状态版本倒序返回,limit 默认 20,允许 1~100,越界回退 20。字段包括通知 event_id、status_version、event 快照、delivery_status(pending / delivered / failed)、累计 attempts、next_attempt_at、last_http_status、last_error 和最近 20 条 delivery_attempts。尝试记录没有 finished_at 表示进程中断或仍在投递。补发不生成新事件、不改订单状态;已送达或仍待投递的事件重复请求不会额外排队。重试接口按客户端每分钟最多 30 次。

通知与查单并用:未收到通知时查询原单并定期对账;通知投递耗尽不代表支付失败。

6. 服务端查单与对账

方法与路径权限用途
GET /openapi/v1/merchant-payments/{order_no}merchant_payments.read查询本商户一单,HTTP 200 返回收款单对象
GET /openapi/v1/merchant-paymentsmerchant_payments.read按本商户外部引用或 TDCloud 单号过滤,HTTP 200 返回 {"items": [...]}

列表必须提供至少一个 external_reference 或 order_no;两者同时提供时共同匹配。limit 默认 20,范围 1–100,非法或越界回退 20。按最新记录优先返回,不提供页码、总数或完整商户订单分页。

curl "{API_BASE_URL}/openapi/v1/merchant-payments/{ORDER_NO}" \ -H "Authorization: Bearer {ACCESS_TOKEN}" curl --get "{API_BASE_URL}/openapi/v1/merchant-payments" \ -H "Authorization: Bearer {ACCESS_TOKEN}" \ --data-urlencode "external_reference=merchant-order-123" \ --data-urlencode "limit=20"

单笔结果包含建单返回的字段;下列字段用于确认支付:

字段类型说明
statusstring收款单状态,见下表
status_versioninteger同单状态版本,防止旧通知覆盖新状态;历史未变更订单可为 0
event_idstring,可省略确认支付后的稳定、唯一支付事件号;用于商户幂等记账
provider_trade_nostring,可省略渠道交易号;TDC 为 TDC:{order_no}
occurred_atstring 或 null确认支付时间,RFC 3339,保留响应中的时区
settlement_tdcstring,可省略平台渠道扣除商户手续费后的净结算 TDC,按八位定点整数表示;非支付凭证
return_urlstring,可省略已保存的商户返回地址

| fee_status | string | unselected 未选择付款方式、quoted 已锁定费用、legacy 沿用历史订单费用 | | fee_version | integer | 费用快照版本;历史订单为 0 | | payment_amount / payment_currency | string,可省略 | 买家实付金额(含买家手续费)及实际付款币种;十进制字符串 | | buyer_fee | string,可省略 | 买家承担的手续费,使用 payment_currency,不计入商户收入 | | merchant_fee | string,可省略 | 该单商户手续费,使用 payment_currency | | merchant_fee_tdc | string | 商户手续费的 TDC,按八位定点整数表示 | | gross_settlement_tdc | string | 订单原金额折算的 TDC,扣除商户手续费前的金额;同样为八位定点整数 |

已支付响应示例(仅展示核对字段):

{ "order_no": "MP_EXAMPLE", "external_reference": "merchant-order-123", "payment_no": "CHANNEL_NO", "amount": "10.50", "amount_minor": 1050, "currency": "USD", "currency_decimals": 2, "status": "paid", "event_id": "MPE_EXAMPLE", "provider_trade_no": "pi_EXAMPLE", "occurred_at": "2026-10-08T13:45:00+08:00" }

expires_at 同样为 RFC 3339 时间,不是 Unix 秒。单号、事件号和渠道交易号按字符串保存。服务端状态通知可触发商户处理,但仍应保留有间隔、有超时上限的查单和定期对账。

状态含义与处理
pending未决,继续核对;不能交付,也不能仅凭本地计时判失败
paid收款与商户账务处理已确认;核对订单引用、金额和币种后按 event_id 只记一次
review支付期限已到但渠道结果未决或核对失败;创建响应不明时需平台人工核对,不要换键重复收款
expired已核对无付款的到期状态;晚到的真实收款仍可能被核验并转为 paid,应继续异常对账
refunded已确认退款,保留原支付事件;商户按自己的退款与权益规则处理
chargeback已确认拒付,保留原支付事件;商户处理争议和业务状态

不要套用商品订单接口的数字 status。当前未定义通用 failed、cancelled 或公开取消接口;未来未知状态保留为待核对,不按支付成功处理。

7. 结算、手续费与调试

订单金额、实付金额与净结算

amount、amount_minor、currency 始终表示商户提交的原始业务订单金额,选择支付方式不会修改它们。插件核对业务订单时仍使用这些字段。payment_amount、payment_currency 则表示该方式下买家实际付款,可能包含手续费或 TDC 折算。

平台渠道沿用渠道配置中的两组费用:买家手续费加到实际付款中;商户手续费从订单折算 TDC 中扣除,净额才进入商户钱包并执行冻结策略。买家手续费不计入商户结算收入。收银台在跳转支付前显示每种方式的实付和手续费,商户收款详情显示折算金额、商户手续费和净结算。

费用按实际付款币种计算:固定费用先加到计费基数,再计算百分比费用;百分比封顶只限制百分比部分。买家费用基于订单支付小计,平台渠道的商户费用基于含买家费用的实际付款。费用按付款币种最小单位四舍五入,正费用不足一个最小单位时收取一个最小单位;配置全部为零时为零费用。TDC 方式先按锁定汇率折算订单金额,再计算 TDC 渠道费用。费用达到或超过可结算订单金额时,该方式无法用于此笔收款。

例如订单 CNY 10.00、锁定汇率 1 CNY = 1 TDC,买家和商户两组配置均为固定 4 加 4%(未触及封顶):

项目金额
原订单金额CNY 10.00
买家手续费CNY 4.56
买家实付CNY 14.56
原订单折算10.00 TDC
商户手续费4.74 TDC
商户净结算5.26 TDC

该示例不代表平台固定费率或汇率。金额、费率规则、折算结果和冻结策略按建单快照保存,切换方式只预览该单已保存的对应报价,确认付款时才绑定方式。尚未选择方式时没有统一的实付或净结算报价;历史订单继续按原记录收款、验额和结算,不按当前费率补扣。

通知和查单中的原始订单金额保持不变;TDCloud 会使用含买家费用的实付金额验证支付提供商结果。退款和拒付同样核对原支付实付,不用原始订单金额代替实付。完整退款可能超出商户的净冻结款,差额按平台规则从担保金等资金承担;已收手续费不返还。附加的外部不可返还费用只计新增损失,不能再次加入已计入实付差额的手续费。

平台渠道按建单汇率折算并扣除商户手续费后,将净 TDC 记入商户钱包;平台按商户配置 0–30 天冻结,0 天可实时使用。商户自有渠道由商户自行收款,TDCloud 不重复入账;平台手续费在建单时检查资金,在获取支付链接前再次检查并预占,优先使用可用 TDC,再使用已获批授信。无法筹足则拒绝交易。

投诉先阻止该单冻结销售款释放,核实损失后依次使用该单冻结款、担保金、可用余额及待追回余额处理。不可返还的手续费可能导致损失超出冻结款。退款、拒付和投诉处置由平台核验,不能用修改商户业务订单代替平台账务动作;本页没有商户自助退款/提现 OpenAPI。更多操作见 支付与结算。

test_mode: true 仅表示管理员指定分配的 Stripe 测试渠道。消费者不发生真实 Stripe 扣款,但 TDCloud 正常订单、账务、钱包 TDC 和冻结流程仍执行。测试权限不由管理员身份自动获得,也不代表可随意混用生产业务;测试账号、商品和交付由管理员维护。

调试配置只填写商户时,指定商户的所有买家可使用所选测试渠道;只填写付款用户时,这些用户可在所有商户下使用;同时填写时,商户与付款用户条件须同时满足。两项均为空不授予使用权,多个编号在各自列表内匹配任意一个。

服务端渠道目录和建单没有买家身份,先按商户范围检查。存在付款用户限制的测试渠道会在目录中返回 login_required: true;建单成功不代表任意买家均可付款。收银台按实际 TDCloud 登录用户检查,生成或再次获取渠道支付链接前再次检查;请求中的自报买家编号不能授予调试权限。付款用户限制要求登录,即使商户已允许未登录消费。已发出的渠道会话仍可能在撤销调试权限后成功,已验证收款继续正常入账。

8. 错误、限流与接入检查

错误至少包含字符串 error。HTTP 202 的 provider_result_pending 也不是支付成功。按 HTTP 状态和错误码分支,不依赖中文文案。

HTTPerror处理
400invalid_notify_config开启单笔通知需提供地址和密钥或启用商户默认通知;关闭单笔通知不能同时传地址或密钥
400invalid_notify_url使用公网 HTTPS 通知地址,不能包含账号密码、片段或内网目标
400invalid_notify_secret通知地址须配独立随机密钥,32~256 字节,不含空白
503notification_unavailable稍后用原幂等键重试
400invalid_request核对参数、旧金额字段及列表过滤条件
400invalid_amount使用合法的正数十进制字符串,不超出金额范围,不同时提交两种金额;返回 field: "amount" 和说明
400invalid_amount_precision金额包含此币种不支持的非零小数位;平台不舍入,返回 field: "amount" 和说明
422currency_unavailable订单计价币种不存在或未开放;返回 field: "currency" 和说明
400invalid_expires_in修正有效期为 60~7200 秒的整数;返回 error_description 和 field: "expires_in"
400invalid_return_url修正 HTTPS 地址;同时返回 error_description、field: "return_url"
401invalid_token重新获取有效 OAuth 令牌
403insufficient_scope、client_credentials_required核对批准权限及令牌主体
403merchant_inactive请平台恢复绑定商户
403login_required收银台要求买家登录
403self_payment_not_allowed不能用本人的 TDC 余额向本人商户付款;改用其他付款账号或方式
422insufficient_balance买家可用 TDC 余额不足;充值或选择其他方式
422provider_checkout_rejected渠道明确拒绝创建付款页面;预占已释放,可选择其他方式
403payment_debug_access_denied核对调试渠道分配与启用状态
404payment_not_found核对单号及本商户归属,不推断其他商户资源
409payment_conflict原幂等键参数冲突;收银台支付状态冲突也可能使用此码
410payment_expired不能继续发起支付;查询原单并核对付款结果,避免重复下单
409provider_result_mismatch由平台核对渠道会话、金额和币种
422channel_unavailable、currency_rate_unavailable重新确认渠道、币种及平台汇率
422merchant_fee_funding_unavailable核对平台费率、可用钱包和授信额度
202provider_result_pending渠道结果未明,保留原单与原支付尝试;这是待核对响应,不是付款成功
429rate_limited按 Retry-After 等待,避免持续重试
503rate_limit_unavailable限流服务暂不可用,有限退避重试
500server_error保存脱敏上下文并向平台反馈;写请求复用原幂等键

建单每客户端每分钟 60 次;查单、过滤列表与渠道目录共用每客户端每分钟 300 次。收银台按 IP 限速:查询 180 次、发起支付 30 次/分钟。

完成接入后,检查动态金额、支付返回页、同键重试及参数冲突、商户权限、未登录消费、支付超时和异步结果。确认业务订单只按稳定 event_id 更新一次,并按退款、拒付结果处理后续业务。Stripe Webhook 验签由 TDCloud 完成。

最后更新于