Skip to main content
本页回答商户关于绑卡和基于 token 支付最常问的问题。 字段级契约在 Tokenization API 规范 和 收单 API 规范。

什么是卡 Tokenization,tokenId 是什么?

Tokenization 用一个可复用的 tokenId 替代用户的原始卡信息。 在你这边安全地存储 tokenId;发起用户支付或 后端扣款时,用它代替卡信息。支持的 tokenType 是 CARD。一旦持有 token,你可以把它用于一次性 支付,以及你自己管理的订阅式扣款,按计划 或不按计划。

我如何绑卡并获取 token?

标准流程让原始卡数据不经过你的服务器:
  1. 调用 /api/v1/tokenization/generate,带唯一的 tokenRequestId (幂等键)、你的 merchantUserId、tokenType: "CARD" 和一个 notifyUrl。响应返回一个 tokenSessionId。
  2. 在你的前端,初始化 Waffo JavaScript SDK (@waffo/payment-sdk)并调用 tokenizationSubmit(tokenSessionId, tokenData)。 SDK 在把卡数据发送给 Waffo 之前会加密。卡的 expiry 接受 MM/YYYY(输入时也接受 MM/YY),但查询和通知 始终返回 MM/YYYY。
  3. Waffo 向你的 notifyUrl 推送一条 TOKENIZATION_NOTIFICATION Webhook 通知, 携带 tokenId、tokenStatus 和脱敏的卡信息 (maskedCardInfo、cardBin、cardScheme、cardType 等)。
  4. 随时使用 /api/v1/tokenization/inquiry 查询 token 详情——按 tokenId(返回一条)或按 merchantUserId(可能返回多条)。
如果你的组织持有处理原始持卡人数据所需的 PCI-DSS 认证, 你可以改为在 /api/v1/tokenization/generate 的 tokenData 对象中直接传 pan、name、expiry 和 cvv;在这种 情况下 tokenId 会在 API 响应中同步返回。

token 的生命周期是什么样的?

tokenStatus 有四个值: 每当 token 状态变化或 token 数据更新时,你会收到一条 TOKENIZATION_NOTIFICATION。处理后回复 success;如果 Waffo 收到 failed 或 unknown,Waffo 会在接下来一天内按退避 计划重试通知;计划参见 Webhook 通知重试。

tokenSessionId 和 tokenId 各有效多久?

两个不同的时钟,其中只有一个是固定期限: 所以即将过期的卡产生的 token 会在其有效期月份结束时停止可用, 即使它是今天绑定的;而有效期很远的卡产生的 token 会跑完整个平台有效期。 两个实际后果:
  • token 自身的过期时间戳不在 /api/v1/tokenization/inquiry 的响应中。你拿回的是 tokenStatus 加上 token 数据中的卡 expiry——如果你想在续订失败前提醒用户, 这足以让你自己推导出上述规则。
  • tokenStatus 由周期性扫描而不是在 token 失效的那一秒 转为 EXPIRED,所以 token 可能在略过其计算出的过期时间后 仍显示为可用。按过期规则安排;把状态和 订单创建错误码当作最终定论。

同一个用户把同一张卡绑两次,我会得到两个 tokenId 吗?

不会。卡 token 在重新绑定时会去重:当以下全部 与一个未被移除的 token 匹配时,你会拿回已有的 tokenId——你的 merchantId(加上 subMerchantId,如果你传了)、相同的 merchantUserId、相同的卡、相同的持卡人姓名,以及相同的 tokenType。 值得围绕它设计的:
  • 你不需要自己对已保存的卡列表去重;但要以 tokenId 作为你自己 存储的键,因为第二次绑定返回的是第一个 token 而不是 新的。
  • merchantUserId 是键的一部分,所以两个不同的 merchantUserId 绑定同一张实体卡会得到两个不同的 tokenId。没有 跨用户的卡标识暴露给你用于关联。
  • 同一张卡上不同的持卡人姓名被视为不同的 凭据,会产生新的 token。
  • /api/v1/tokenization/remove 之后,该 token 从查询中排除且 永不复用——再次绑定该卡会发放一个新的 tokenId。
两个绑定调用都是幂等的,方式不同:

CIT 和 MIT 有什么区别,各在什么时候用?

两条 MIT 特有的规则需要注意:
  • CIT 可以用刚创建的 token——首次支付就是验证卡的过程, 所以你不需要等待”已验证”状态。
  • MIT 需要一个已经可用的存储凭据。 如果 token 从未 完成过成功支付(或其存储凭据已不再有效), MIT 扣款会以 A0045 被拒绝。实践中:首次扣款用 CIT,之后的扣款用 MIT。
  • threeDsDecision 字段(3DS_FORCE / NO_3DS)只对 卡 / ApplePay / GooglePay 的 CIT 支付有效;对 MIT 会被忽略。

首次支付和后续扣款如何衔接?

  1. 绑卡并获取 tokenId(见上文)。
  2. 等待 token 到达可扣款状态——关注 TOKENIZATION_NOTIFICATION 或轮询 /api/v1/tokenization/inquiry。
  3. 对于用户参与的支付,用 userPaymentAccessToken 创建 CIT 订单。
  4. 对于之后你自己发起的扣款,用 merchantInitiatedMode 创建 MIT 订单 (scheduled 用于你管理的固定节奏, unscheduled 用于事件驱动的扣款)。

为什么 /order/create 返回了 AUTHORIZATION_REQUIRED 而没有扣我已保存的 token?

因为针对已保存 token 的 CIT 不是服务端扣款。当你发送 userPaymentAccessToken 而不带 merchantInitiatedMode 时,Waffo 创建 订单并以 orderStatus: AUTHORIZATION_REQUIRED 和填充了的 orderAction 返回。此时还没有资金流动;持卡人仍有一步要完成。 这是一键 CIT 的正常结果,不是错误。 该怎么处理:
  1. 解析 orderAction 并读取 actionType——WEB 表示把用户重定向到 webUrl,DEEPLINK 表示重定向到 deeplinkUrl。
  2. 在 Waffo 的托管收银台上,已保存的卡已被选中并以脱敏形式显示; CVV 通常是用户唯一需要填写的字段。之后可能跟随 3DS 挑战。
  3. 把 AUTHORIZATION_REQUIRED 视为非终态,等待支付 通知(或轮询订单查询)获取结果。
绝不要仅基于”/order/create 是否返回成功”分支——要基于 orderStatus 分支,并且只要 orderAction 存在,就假设有一个用户步骤 尚未完成。 如果你需要在没有顾客在场的情况下扣款,那正是 merchantInitiatedMode 的用途;参见上文的 CIT/MIT 章节。

token 过期了或支付被拒绝了,我该怎么办?

  • 订单创建时的 A0037(用户支付 token 无效 / 已过期)或 A0023(因 token 过期无法创建订单):存储的 token 已 不可用。调用 /api/v1/tokenization/remove 解绑它(按 tokenId,或按 merchantUserId 解绑用户的所有 token),然后让用户 绑定新卡。
  • 绑定期间的 B1002(卡已过期)或 B1001(卡信息无效): 问题在卡本身——用户必须提供有效的卡。
  • B1005(token 会话 ID 已过期):generate 返回的 tokenSessionId 已不再有效——再次调用 /api/v1/tokenization/generate。
  • B1003(超出绑卡数量限制)和 B1004(当前商户合同不支持 该卡组织):这些取决于你签约的 配置——请查看商户 Portal 或联系集成支持。

我在支付过程中绑卡。Tokenization 结果通知到哪里?

在商户 Portal(Settings → Integration)中针对你的 API key 配置一个专用的 Tokenization 通知 URL。Waffo 会把它快照到用该 key 创建的每个 订单上,绑卡结果会通知到那里。
  • 它是一个独立通道:你的支付结果 notifyUrl 照常继续接收 支付通知。
  • 它不是订单创建参数——你不能按订单覆盖它。
  • 如果未配置,Tokenization 通知行为不变。

我能设置用户的默认卡吗?

可以,通过一个专用端点而不是在订单创建时。调用 /api/v1/saved-payment-methods/config,带上 token 和你想要的操作: 默认卡用于对顾客在收银台看到的已保存卡列表排序—— 过期的卡被推到列表末尾。

用户的卡被银行换新了。存储的 token 还能用吗?

不要假设能用。Waffo 目前不会自行根据发卡行侧的更新 刷新存储的卡,所以请为重新绑定做好计划:
  • 关注报告 token 不再可用的 Tokenization 和支付通知, 并提示用户再次绑卡。
  • 如果卡在钱包或发卡行侧被解绑,存储的凭据 会变为不可用且无法重新激活。
  • 过期的 token 不能再扣款,但你仍可以调用 /api/v1/tokenization/remove 解绑它,然后再向用户索要新的 卡凭据。
对于订阅,在订阅上保留一个备用支付方式是 实际的保障——参见 订阅生命周期。