Appearance
商户 Webhook
商户 Webhook 用于接收 FuturePay UCard 主动发送的业务事件通知。
接入流程
- 登录 FuturePay 商户管理后台,在 UCard 的“租户回调配置”中填写自己的 Webhook URL 并启用。每个商户同时只允许启用一个回调地址。
- 在该 URL 上提供可公开访问的 HTTP 接口,接收 FuturePay 发送的
POST application/json请求。 - 使用请求 Header 和未经修改的原始请求体完成平台签名校验。
- 读取 Payload 中的
eventType,根据事件类型执行不同的业务处理。 - 使用
eventNo做幂等处理,成功接收后返回 HTTP 2xx。
所有支持的 UCard 事件都会发送到同一个已启用的 Webhook URL。商户不需要为不同事件配置多个地址,应在自己的接收服务中按 eventType 分发。
历史事件兼容说明
新建事件统一使用 schemaVersion: 2,且 eventType 只表示业务场景。为保持原始请求体、签名和重放幂等不变,历史 PENDING/DEAD 事件重放时仍可能携带状态型 eventType,卡提现旧事件也可能没有 eventType。商户应继续以 eventNo 幂等,并对历史格式保留兼容解析。
回调请求
FuturePay 使用以下请求方式:
| 项 | 说明 |
|---|---|
| HTTP 方法 | POST |
| Content-Type | application/json |
| 请求地址 | 商户管理后台中已启用的 Webhook URL |
| 请求超时 | 10 秒 |
| 成功响应 | 任意 HTTP 2xx |
HTTP 3xx、4xx、5xx、连接异常或超时均视为投递失败。建议使用 HTTPS,并在 10 秒内完成验签和可靠落库;耗时业务可在落库后异步处理。
签名 Header
每次 Webhook 请求都会携带以下 Header:
| Header | 说明 |
|---|---|
X-FP-Timestamp | FuturePay 生成签名时的毫秒级时间戳。 |
X-FP-Api-Key | FuturePay 平台 Ed25519 公钥 hex。 |
X-FP-Signature | FuturePay 平台签名 hex。 |
X-FP-Body-Hash | 原始请求体的 SHA-256 hex。 |
签名原文为:
text
X-FP-Timestamp|RAW_CALLBACK_BODY验签时必须使用收到的原始请求体,不能先解析 JSON 再重新序列化。完整算法和密钥说明见 加签说明。
公共字段
| 字段 | 类型 | 说明 |
|---|---|---|
schemaVersion | integer | Payload 结构版本。新建事件固定为 2。 |
eventNo | string | Webhook 事件唯一编号,也是商户幂等键。自动重试和人工重放不会改变该值。 |
eventType | string | 业务场景,用于分发到对应业务处理器,不包含成功或失败状态。 |
status | string | 当前场景的业务状态。具体含义以对应事件为准。 |
failCode | string | 失败码;没有失败信息时为空。 |
failMessage | string | 失败原因;没有失败信息时为空。 |
occurredTime | string | 事件发生时间,格式为 yyyy-MM-dd HH:mm:ss。 |
不同事件会携带各自的业务字段。商户应先识别事件类型,再按对应结构解析,不要假设所有事件 Payload 完全相同。
事件类型
eventType | 说明 |
|---|---|
CARD_OPENING | 开卡场景;通过 status 判断成功或失败。 |
CARD_RECHARGE | 卡充值场景;通过 status 判断成功或失败。 |
CARD_WITHDRAWAL | 卡提现场景;通过 status 判断成功或失败。 |
CARD_CONSUMPTION | 卡消费场景;通过 status、feeCharged 和失败字段判断交易及手续费结果。 |
CARD_MONTHLY | 卡月费场景;通过 status 判断扣取成功或失败。 |
事件业务字段
除公共字段外,不同事件包含以下业务字段:
eventType | status 说明 | 业务字段 |
|---|---|---|
CARD_OPENING | SUCCESS 或 FAILED | cardOrderNo、requestNo、feeAmount、assetCode、cardId、cardAccountId、last4、expiryMonth、expiryYear |
CARD_RECHARGE | SUCCESS 或 FAILED | orderNo、requestNo、cardId、amount、currency、feeAmount、feeCurrency |
CARD_WITHDRAWAL | SUCCESS 或 FAILED | orderNo、requestNo、cardId、amount、feeAmount、platformFeeAmount、tenantFeeAmount、totalAmount、currency |
CARD_CONSUMPTION | 卡交易终态,例如 SUCCESS、COMPLETED、SETTLED、FAILED、REJECTED、CANCELLED 或 CANCELED | providerTransactionId、cardId、cardAccountId、amount、assetCode、countryCode、feeCharged、transactionFee、authorizationFee、totalFee |
CARD_MONTHLY | SUCCESS 或 FAILED | cardId、billingMonth、amount、assetCode |
CARD_CONSUMPTION 的 status 表示卡交易状态;手续费是否处理成功应结合 feeCharged、totalFee、failCode 和 failMessage 判断。
当前 CARD_WITHDRAWAL 的 amount 和 totalAmount 均表示本次提现总扣款金额,即提现本金与手续费之和。
卡消费通知示例
本次卡消费通知使用 countryCode 表示消费国家或地区代码:
json
{
"schemaVersion": 2,
"eventNo": "UCCB202608040001",
"eventType": "CARD_CONSUMPTION",
"providerTransactionId": "TXN202608040001",
"cardId": "CARD001",
"cardAccountId": "ACCOUNT001",
"amount": "100.00",
"assetCode": "USD",
"countryCode": "US",
"feeCharged": true,
"transactionFee": "1.00",
"authorizationFee": "0.00",
"totalFee": "1.00",
"status": "SUCCESS",
"failCode": null,
"failMessage": null,
"occurredTime": "2026-08-04 12:00:00"
}幂等处理
FuturePay 采用至少一次投递语义,同一个事件可能被多次发送。商户必须以 eventNo 为唯一键处理幂等,不能只使用 eventType、订单号或交易号去重。
推荐处理顺序:
- 校验平台签名。
- 在数据库中插入
eventNo,并建立唯一约束。 - 如果
eventNo已存在,直接返回 HTTP 2xx。 - 根据
eventType执行业务处理。 - 提交本地事务后返回 HTTP 2xx。
如果先返回 2xx、后异步落库,进程异常可能造成通知丢失。若业务处理耗时较长,建议先可靠保存原始事件,再异步消费。
重试规则
- 首次投递失败后,FuturePay 会继续扫描待投递事件并重试。
- 每个事件最多自动尝试 3 次。
- HTTP 非 2xx、连接异常和 10 秒超时都会占用一次尝试。
- 自动重试以及平台人工重放均保持原始
eventNo和请求体不变。 - 三次自动尝试均失败后,平台停止自动投递,但运营人员仍可能人工重放,因此商户不能在任何时间窗口后关闭幂等保护。
- 商户不应依赖固定重试间隔,也不应假设不同事件严格按发生顺序到达。
接入检查
- 已在商户管理后台配置并启用正确的 Webhook URL。
- 接口可接收
POST application/json,并在 10 秒内返回。 - 使用原始请求体完成
X-FP-*签名校验。 - 根据场景型
eventType分发业务处理,并兼容历史状态型事件格式。 - 数据库对
eventNo建立唯一约束。 - 重复事件返回 HTTP 2xx,不重复执行资金或订单状态变更。
