EasyCards VCC API 对接手册#
更新日期:2026-08-14
本文说明 EasyCards VCC API 的鉴权方式、调用顺序、资源状态和 Webhook 事件。字段类型、必填项和响应结构以 API 参考 为准;可执行请求以 Postman Collection 为准。
1. 接口环境#
| 环境 | Base URL |
|---|---|
| 沙箱 | https://sandbox.easycards.io |
| 生产 | 完成生产环境配置后在 EasyCards Portal 中获取 |
1.1 鉴权#
使用以下请求头:
Authorization: Bearer <PAYMENT_API_KEY>
Content-Type: application/json
1.2 权限#
| 权限 | 接口范围 |
|---|---|
payment.vcc.read |
产品、客户、申请、卡片、余额、充值和交易查询 |
payment.vcc.customer.manage |
创建或修改客户、上传私有文件 |
payment.vcc.card.create |
提交开卡申请 |
payment.vcc.card.sensitive |
获取加密卡敏感信息 |
payment.vcc.card.topup |
提交卡充值 |
payment.vcc.card.withdraw |
提交共享卡提现 |
payment.vcc.card.status |
冻结和解冻卡片 |
2. 通用规则#
2.1 成功响应#
{
"code": 0,
"message": "OK",
"data": {}
}
2.2 错误响应#
{
"code": "VALIDATION_ERROR",
"message": "One or more request fields are invalid.",
"data": null
}
程序判断顺序:
- HTTP 状态码。
- 顶层
code。 - 对应资源的状态字段。
2.3 状态字段#
| 资源 | 状态字段 |
|---|---|
| 客户 | customer_status |
| 开卡申请 | application_status |
| 卡片 | card_status |
| 充值 | topup_status |
| 共享卡提现 | withdrawal_status |
| 冻结、解冻响应 | resource_status |
| 交易 | transaction_status |
PENDING 为处理中,SUCCESS 和 FAIL 为终态。卡片当前状态以 card_status 为准。
2.4 request_id#
所有写接口使用 request_id:
- 类型:字符串。
- 长度:1–64 个字符。
- 同一业务请求的重试使用相同
request_id和相同参数。 - 相同
request_id配合不同参数时返回IDEMPOTENCY_CONFLICT。
示例:
merchant-customer-C202607280001
merchant-card-O202607280001
merchant-topup-T202607280001
merchant-withdrawal-W202608130001
merchant-freeze-F202607280001
2.5 金额与时间#
- 金额字段使用字符串。
- 金额响应保留两位小数。
- 充值请求金额大于
0,最多两位小数。 - 提现请求金额大于
0、最多两位小数,且不得超过共享卡当前未使用可用额度。 - 币种使用大写代码。
- 时间字段使用 Unix 秒级时间戳。
2.6 分页#
列表接口使用:
| 参数 | 默认值 | 范围 |
|---|---|---|
limit |
20 |
1–200 |
offset |
0 |
大于或等于 0 |
3. 账户#
账户接口使用与 VCC 接口相同的 Base URL 和 Bearer Token。账户余额是账户维度的资金余额,与单张卡片的余额不同。
3.1 查询当前账户#
GET /payment/account
请求不包含 Path、Query 或 Body 参数。成功响应的 data.account 包含:
| 字段 | 类型 | 说明 |
|---|---|---|
merchant_id |
string | 商户标识 |
account_id |
string | 当前账户标识 |
name |
string | 账户名称 |
status |
string | 账户状态 |
currencies |
array | 支持的币种列表 |
default_currency |
string | 默认币种 |
timezone |
string | 账户时区 |
created_at / updated_at |
integer | 创建 / 更新时间,Unix 秒 |
3.2 查询账户余额#
GET /payment/balances
可选 Query 参数 currency 用于按币种筛选;不传时返回全部币种。响应的 data.balances 中每项包含:
| 字段 | 类型 | 说明 |
|---|---|---|
account_id |
string | 账户标识 |
currency |
string | 大写币种代码 |
currency_type |
string | fiat 或 crypto |
balance |
decimal | 账户总余额 |
available |
decimal | 可用余额 |
frozen |
decimal | 冻结余额 |
updated_at |
integer | 更新时间,Unix 秒 |
3.3 查询入金记录#
GET /payment/deposits
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
currency |
string | 否 | 币种筛选 |
network |
string | 否 | 网络筛选 |
status |
string | 否 | 入金状态筛选 |
start_at / end_at |
integer | 否 | 开始 / 结束时间,Unix 秒 |
limit / offset |
integer | 否 | 分页参数 |
响应的 data.deposits 为入金记录数组。每项包含 account_id、deposit_id、currency、network、txid、amount、status、confirmations、reference、occurred_at 和 created_at。data.total 和 data.total_pages 分别为总记录数和总页数。
3.4 查询账本流水#
GET /payment/ledger
请求参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
currency |
string | 否 | 币种筛选 |
record_type |
string | 否 | 业务记录类型筛选 |
start_at / end_at |
integer | 否 | 开始 / 结束时间,Unix 秒 |
limit / offset |
integer | 否 | 分页参数 |
sort_by |
string | 否 | 排序字段 |
sort_order |
string | 否 | 排序方向 |
响应的 data.entries 为账本流水数组。每项包含账户和流水标识、分录类型、业务类型、交易类型、业务记录类型、凭证字段、币种、变动金额、变动后余额、业务参考号和创建时间。data.total 和 data.total_pages 分别为总记录数和总页数。
4. 调用顺序#
4.1 开卡主流程#
图中实线表示同步 HTTP 请求或响应,虚线表示 EasyCards 主动发送的异步 Webhook 通知。PENDING 是同步响应中的业务状态,不代表 HTTP 请求仍未返回。
sequenceDiagram
autonumber
participant M as 商户系统
participant E as EasyCards API
Note over M,E: 阶段一:读取开卡要求
M->>E: 查询可用产品及开卡要求 · GET /payment/vcc/products
E->>M: [同步响应] product_code、card_mode、费用、限额、required_customer_fields
opt 产品字段要求上传文件
M->>E: 上传客户文件并取得文件标识 · POST /payment/vcc/files
E->>M: [同步响应] file_id
end
Note over M,E: 阶段二:创建客户并提交开卡申请
M->>E: 创建持卡人资料 · POST /payment/vcc/customers
E->>M: [同步响应] customer_id、customer_status
M->>E: 为客户提交开卡申请 · POST /payment/vcc/card-applications
E->>M: [同步受理响应] application_id、application_status
Note over M,E: 阶段三:接收状态通知并查询最终结果
opt application_status = PENDING
E-->>M: [异步通知] vcc.application.updated · 状态或 next_action 变化
end
M->>E: 查询开卡申请当前结果 · GET /payment/vcc/card-applications/{application_id}
E->>M: [同步响应] application_status;成功时包含 card_id
opt application_status = SUCCESS
M->>E: 查询卡片状态与基本信息 · GET /payment/vcc/cards/{card_id}
E->>M: [同步响应] card_status、卡片基本信息
end
4.2 卡片后续操作#
充值、共享卡提现、冻结和解冻接口先同步返回受理结果;需要后续处理时,再通过对应 Webhook 通知状态变化。余额查询和敏感数据获取在当前 HTTP 请求内同步返回。
sequenceDiagram
participant M as 商户系统
participant E as EasyCards API
opt 查询卡片资金信息
M->>E: 查询单张卡片当前余额 · GET /payment/vcc/cards/{card_id}/balance
E->>M: [同步响应] balance、available、frozen
end
opt 获取卡片敏感数据
M->>E: 获取 RSA 加密卡数据 · POST /payment/vcc/cards/sensitive
E->>M: [同步响应] encrypt_data
end
opt 卡片充值或共享卡额度调增
M->>E: 通过统一充值接口提交金额 · POST /payment/vcc/cards/{card_id}/topups
E->>M: [同步受理响应] topup_id、topup_status
E-->>M: [异步通知] vcc.topup.updated · 充值状态变化
M->>E: 查询充值当前结果 · GET /payment/vcc/topups/{topup_id}
E->>M: [同步响应] topup_status、金额与费用
end
opt 撤回共享卡未使用额度
M->>E: 提交共享卡提现 · POST /payment/vcc/cards/{card_id}/withdrawals
E->>M: [同步受理响应] withdrawal_id、withdrawal_status
E-->>M: [异步通知] vcc.withdrawal.updated · 提现状态变化
end
opt 冻结或解冻卡片
M->>E: 提交卡片状态变更 · POST .../freeze 或 POST .../unfreeze
E->>M: [同步受理响应] resource_status
E-->>M: [异步通知] vcc.card.updated · 冻结或解冻终态
M->>E: 查询卡片当前状态 · GET /payment/vcc/cards/{card_id}
E->>M: [同步响应] card_status
end
5. 产品#
5.1 查询可用产品#
GET /payment/vcc/products
权限:payment.vcc.read
请求参数:
| 位置 | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| Query | limit |
integer | 否 | 最大返回记录数,默认 20,范围 1–200 |
| Query | offset |
integer | 否 | 跳过的记录数,默认 0 |
响应中的 data.products 为产品数组,data.total 为符合条件的产品总数。每个产品包含:
| 字段 | 类型 | 说明 |
|---|---|---|
product_code |
string | 产品代码,提交开卡申请时使用 |
product_name |
string | 产品展示名称 |
card_form |
string | 卡片形式:VIRTUAL 或 PHYSICAL |
card_mode |
string | 资金模式:PREPAID_CARD(预充值卡)或 BUDGET_CARD(共享卡) |
settlement_currency |
string | 大写结算币种代码 |
open_fee_amount |
string | 开卡费,固定两位小数 |
kyc_fee_amount |
string | KYC 费用,开卡成功时收取,固定两位小数 |
reversal_fee_amount |
string | 每笔成功撤销交易的固定费用,固定两位小数 |
refund_fee_rate |
string | 每笔成功退款的费率小数;0.01 表示 1% |
cross_border_fee_rate |
string | 确认跨境交易时收取的平台费率小数 |
three_ds_fee_amount |
string | 每个唯一 3DS 挑战收取的固定费用,固定两位小数 |
platform_authorization_fee_amount |
string | 每笔成功授权收取的平台固定费用,固定两位小数 |
initial_topup_amount |
string | 开卡时预留的初始卡余额,固定两位小数 |
initial_topup_fee_amount |
string | 初始充值手续费,固定两位小数 |
total_open_debit_amount |
string | 开卡总扣款金额,固定两位小数 |
topup_fee_rate |
string | 充值手续费率 |
min_topup_amount |
string | 最低充值金额 |
max_topup_amount |
string | 最高充值金额;0.00 表示未配置上限 |
required_customer_fields |
array | 该产品要求的附加客户字段 |
required_customer_fields 中的字段定义:
| 字段 | 说明 |
|---|---|
field_name |
提交到 additional_customer_data 的 Key |
field_label |
展示名称 |
value_type |
字段值类型 |
field_hint |
面向商户的输入提示 |
value_format |
预期值格式 |
min_length / max_length |
字符长度限制 |
accepted_values |
可选值;提交其中的 value |
card_mode 是资金路径的权威字段,商户应保存产品和卡详情返回的值:PREPAID_CARD 的主动充值从当前 API Key 所属账户钱包扣款;BUDGET_CARD 的主动充值表示共享卡额度调增,本金与费用走卡片绑定的共享账户。两种模式复用同一个充值接口、查询接口和 vcc.topup.updated 事件。
6. 文件#
6.1 上传私有文件#
POST /payment/vcc/files
Content-Type: multipart/form-data
权限:payment.vcc.customer.manage
请求字段:
| 位置 | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| Form Data | file |
file | 是 | JPG/JPEG、PNG 或 PDF;单个文件最大 2 MiB |
成功响应的 data.file_id 是平台文件标识。产品要求文件类型的客户字段时,将该值提交到 additional_customer_data 对应的 field_name。
{
"code": 0,
"message": "OK",
"data": {
"file_id": "file_0123456789abcdef"
}
}
7. 客户#
客户对象的主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
customer_id |
string | 平台客户标识 |
first_name / last_name |
string | 名字 / 姓氏 |
gender |
string | male、female 或 unknown |
email |
string | 电子邮箱 |
phone_country_code |
string | 国际电话国家区号 |
mobile_number |
string | 手机号,不包含国家区号 |
date_of_birth |
string | 出生日期,格式 yyyy-MM-dd |
city |
string | 城市 |
state_or_province |
string | 州或省 |
residence_country |
string | 居住国家或地区代码 |
nationality |
string | 国籍代码 |
street_address |
string | 街道地址 |
postal_code |
string | 邮政编码 |
customer_status |
string | 客户状态 |
additional_customer_data |
object | 产品要求的附加客户数据 |
created_at / updated_at |
integer | 创建 / 更新时间,Unix 秒 |
7.1 创建客户#
POST /payment/vcc/customers
权限:payment.vcc.customer.manage
请求字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 本次创建请求的幂等标识 |
first_name |
string | 是 | 客户名字 |
last_name |
string | 是 | 客户姓氏 |
gender |
string | 是 | male、female 或 unknown |
email |
string | 是 | 客户电子邮箱 |
phone_country_code |
string | 是 | 国际电话国家区号 |
mobile_number |
string | 是 | 仅使用 ASCII 数字 0–9 |
date_of_birth |
string | 是 | 格式 yyyy-MM-dd |
city |
string | 是 | 客户所在城市 |
state_or_province |
string | 是 | 客户所在州或省 |
residence_country |
string | 是 | 大写 ISO 3166-1 alpha-2 代码 |
nationality |
string | 是 | 大写 ISO 3166-1 alpha-2 代码 |
street_address |
string | 是 | Trim 后 2–40 个 ASCII 字符,正则:^[A-Za-z0-9 ]+$;仅允许英文字母、数字和普通半角空格,不允许任何连字符或其他符号 |
postal_code |
string | 是 | 客户邮政编码 |
additional_customer_data |
object | 否 | 按产品 required_customer_fields 提交的扩展字段 |
请求示例:
{
"request_id": "merchant-customer-C202607280001",
"first_name": "Alex",
"last_name": "Chen",
"gender": "male",
"email": "alex.chen@example.com",
"phone_country_code": "+86",
"mobile_number": "13800138000",
"date_of_birth": "1990-01-02",
"city": "Shanghai",
"state_or_province": "Shanghai",
"residence_country": "CN",
"nationality": "CN",
"street_address": "100 Century Avenue",
"postal_code": "200120",
"additional_customer_data": {
"id_type": "PASSPORT",
"id_number": "TR1234567"
}
}
成功响应返回 data.customer。保存其中的 customer_id;其余字段为已保存的客户资料和当前 customer_status。
7.2 查询客户列表#
GET /payment/vcc/customers?limit=20&offset=0
权限:payment.vcc.read
请求使用通用分页参数 limit 和 offset。响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.customers |
array | 客户对象数组;列表响应不包含 additional_customer_data |
data.total |
integer | 客户总数 |
7.3 查询客户详情#
GET /payment/vcc/customers/{customer_id}
权限:payment.vcc.read
Path 参数 customer_id 为必填的平台客户标识。响应的 data.customer 为客户对象;详情响应中的敏感附加值会被遮蔽,非敏感枚举值保留。
7.4 修改客户#
PATCH /payment/vcc/customers/{customer_id}
权限:payment.vcc.customer.manage
Path 参数 customer_id 指定需要修改的客户。请求体提交新的 request_id 和完整客户资料;客户资料字段及格式与创建客户一致。additional_customer_data 用于新增或覆盖产品字段,枚举字段提交 accepted_values[].value。
成功响应返回更新后的 data.customer,字段含义见本章“客户对象的主要字段”。
8. 开卡申请#
8.1 提交申请#
POST /payment/vcc/card-applications
权限:payment.vcc.card.create
请求字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 本次开卡申请的幂等标识 |
customer_id |
string | 是 | 已创建的平台客户标识 |
product_code |
string | 是 | 产品查询接口返回的产品代码 |
{
"request_id": "merchant-card-O202607280001",
"customer_id": "cus_0123456789abcdef",
"product_code": "1103"
}
成功响应的 data.application 包含:
| 字段 | 类型 | 说明 |
|---|---|---|
request_id |
string | 请求中的幂等标识 |
application_id |
string | 平台开卡申请标识 |
customer_id |
string | 客户标识 |
product_code |
string | 产品代码 |
application_status |
string | PENDING、SUCCESS 或 FAIL |
created_at |
integer | 创建时间,Unix 秒 |
8.2 查询申请列表#
GET /payment/vcc/card-applications?limit=20&offset=0
权限:payment.vcc.read
请求使用通用分页参数。响应的 data.applications 为申请对象数组,data.total 为申请总数。每项包含申请标识、客户标识、产品代码、状态、金额、结果字段和时间字段。
8.3 查询申请详情#
GET /payment/vcc/card-applications/{application_id}
权限:payment.vcc.read
Path 参数 application_id 为必填的平台开卡申请标识。响应的 data.application 主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
application_status |
string | PENDING、SUCCESS 或 FAIL |
next_action |
object | 待完成动作;没有待处理动作时为空 |
open_fee_amount |
string | 开卡费金额快照 |
kyc_fee_amount |
string | KYC 费用快照;仅开卡成功时收取 |
total_debit_amount |
string | 总扣款金额快照 |
settlement_currency |
string | 结算币种 |
card_id |
string | 申请成功后生成的卡片标识 |
failure_code |
string | 终态失败代码 |
failure_message |
string | 终态失败信息 |
created_at / updated_at |
integer | 创建 / 更新时间,Unix 秒 |
next_action.action_type 当前为 COMPLETE_LIVENESS 或 ADD_FUNDS。ADD_FUNDS 可包含 required_account_balance、required_balance_currency 和 expires_at。
9. 卡片#
卡片对象的主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
card_id |
string | 平台卡片标识 |
customer_id |
string | 客户标识 |
product_code |
string | 产品代码 |
card_mode |
string | 开卡时保存的资金模式:PREPAID_CARD 或 BUDGET_CARD |
masked_card_number |
string | 脱敏卡号 |
last_four_digits |
string | 卡号后四位 |
card_status |
string | INACTIVE、ACTIVE、FROZEN 或 CLOSED |
settlement_currency |
string | 卡片结算币种 |
accounting_currency |
string | 开卡费用及共享账户账本扣款使用的账户币种;不适用时省略 |
created_at / updated_at |
integer | 创建 / 更新时间,Unix 秒 |
后续充值和对账应以卡详情返回的 card_mode 快照为准,不要仅按产品名称或卡形式推断资金路径。
9.1 查询卡片列表#
GET /payment/vcc/cards?limit=20&offset=0
权限:payment.vcc.read
请求使用通用分页参数。响应的 data.cards 为卡片对象数组,data.total 为卡片总数。
9.2 查询卡片详情#
GET /payment/vcc/cards/{card_id}
权限:payment.vcc.read
Path 参数 card_id 为必填的平台卡片标识。响应的 data.card 为卡片对象,字段含义见本章“卡片对象的主要字段”。
9.3 查询卡片余额#
GET /payment/vcc/cards/{card_id}/balance
权限:payment.vcc.read
Path 参数 card_id 为必填的平台卡片标识。响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.card_id |
string | 平台卡片标识 |
data.available_balance |
string | 最近同步的可用余额,固定两位小数 |
data.balance_currency |
string | 大写余额币种代码 |
data.accounting_currency |
string | 共享账户账本扣款使用的账户币种;不适用时省略 |
data.updated_at |
integer | 余额快照时间,Unix 秒 |
9.4 获取敏感卡信息#
POST /payment/vcc/cards/sensitive
权限:payment.vcc.card.sensitive
请求字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
card_id |
string | 是 | 平台卡片标识 |
public_key |
string | 否 | 可选的 Base64 编码 RSA-1024 X.509/SPKI 公钥 DER,不含 PEM 头尾和空白字符;商户后台已为当前 API Key 配置公钥时可以省略,省略后使用该配置 |
{
"card_id": "card_0123456789abcdef"
}
如果请求中传入 public_key,仅本次请求使用该公钥覆盖 API Key 配置;否则使用商户后台为当前 API Key 保存的公钥。
成功响应的 data.encrypt_data 是 RSA-1024 加密后再进行 Base64 编码的敏感卡信息 JSON。使用对应的 PKCS#8 私钥和 PKCS#1 v1.5 填充解密后,JSON 包含 card_number、expiry_date 和 cvv。
10. 充值与共享卡提现#
同一个充值接口按卡详情中的 card_mode 自动选择业务路径:
card_mode |
业务含义 | 本金与费用来源 |
|---|---|---|
PREPAID_CARD |
向预充值卡主动充值 | 当前 API Key 所属账户钱包 |
BUDGET_CARD |
调增共享卡可用额度 | 卡片绑定的共享账户 |
两种模式都返回相同的充值对象,并通过充值列表、详情和 vcc.topup.updated 确认终态。充值本金不会重复记为卡交易。
充值对象的主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
request_id |
string | 提交充值时使用的幂等标识 |
topup_id |
string | 平台充值标识 |
card_id |
string | 平台卡片标识 |
topup_status |
string | PENDING、SUCCESS 或 FAIL |
topup_amount |
string | 充值本金快照 |
fee_amount |
string | 充值手续费快照 |
total_debit_amount |
string | 总扣款金额快照 |
settlement_currency |
string | 结算币种 |
failure_code / failure_message |
string | 终态失败代码 / 信息 |
created_at / updated_at |
integer | 创建 / 更新时间,Unix 秒 |
10.1 提交充值#
POST /payment/vcc/cards/{card_id}/topups
权限:payment.vcc.card.topup
Path 参数 card_id 指定充值卡片。请求字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 本次充值请求的幂等标识 |
topup_amount |
string | 是 | 大于 0、最多两位小数,并满足产品充值限额 |
{
"request_id": "merchant-topup-T202607280001",
"topup_amount": "10.00"
}
成功响应返回 data.topup,字段含义见本章“充值对象的主要字段”。
10.2 查询充值列表#
GET /payment/vcc/topups?limit=20&offset=0
权限:payment.vcc.read
请求使用通用分页参数。响应的 data.topups 为充值对象数组,data.total 为充值总数。
10.3 查询充值详情#
GET /payment/vcc/topups/{topup_id}
权限:payment.vcc.read
Path 参数 topup_id 为必填的平台充值标识。响应返回 data.topup,包括充值状态、金额、费用、失败信息和时间字段。
10.4 提交共享卡提现#
该接口用于撤回 card_mode = BUDGET_CARD 共享卡尚未使用的可用额度;预充值卡不支持。提交后可通过提现列表或详情接口查询当前状态,提现状态变化仍会通过 vcc.withdrawal.updated Webhook 异步通知。
POST /payment/vcc/cards/{card_id}/withdrawals
权限:payment.vcc.card.withdraw
Path 参数 card_id 指定共享卡。请求字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 本次 API 调用的幂等标识,1–64 个字符 |
merchant_withdrawal_no |
string | 是 | 商户提现订单号,当前商户账户内唯一;1–64 个字符,可使用字母、数字、_、.、:、- |
withdrawal_amount |
string | 是 | 大于 0、最多两位小数,且不得超过当前未使用可用额度 |
{
"request_id": "merchant-withdrawal-W202608130001",
"merchant_withdrawal_no": "WD202608130001",
"withdrawal_amount": "10.00"
}
成功受理后同步返回:
{
"code": 0,
"message": "OK",
"data": {
"withdrawal": {
"request_id": "merchant-withdrawal-W202608130001",
"withdrawal_id": "wd_0123456789abcdef",
"merchant_withdrawal_no": "WD202608130001",
"card_id": "card_0123456789abcdef",
"withdrawal_status": "PENDING",
"withdrawal_amount": "10.00",
"settlement_currency": "USD",
"created_at": 1786582800,
"updated_at": 1786582800
}
}
}
PENDING 仅表示已受理,不代表提现成功。保存 withdrawal_id 和 merchant_withdrawal_no,并以 vcc.withdrawal.updated 的 resource_status 确认 SUCCESS 或 FAIL 终态。
幂等规则:相同 request_id 必须使用相同参数;同一 merchant_withdrawal_no 再次提交相同 card_id 和金额时返回原提现记录,改用不同卡片或金额时返回 409 CARD_WITHDRAWAL_ORDER_CONFLICT。卡片存在其他额度变更操作时返回 409 CARD_OPERATION_IN_PROGRESS;非共享卡返回 422 CARD_WITHDRAWAL_NOT_SUPPORTED。
10.5 查询共享卡提现#
提交共享卡提现后,可以按商户提现单号、卡片或状态分页查询当前商户账户下的提现记录:
GET /payment/vcc/withdrawals?merchant_withdrawal_no=WD202608130001&card_id=card_0123456789abcdef&withdrawal_status=PENDING&limit=20&offset=0
权限:payment.vcc.read
所有 Query 参数均可选:merchant_withdrawal_no 为商户提现单号,card_id 为平台卡片标识,withdrawal_status 只接受 PENDING、SUCCESS 或 FAIL;limit 默认 20(范围 1–200),offset 默认 0。
{
"code": 0,
"message": "OK",
"data": {
"withdrawals": [
{
"request_id": "merchant-withdrawal-W202608130001",
"withdrawal_id": "wd_0123456789abcdef",
"merchant_withdrawal_no": "WD202608130001",
"card_id": "card_0123456789abcdef",
"withdrawal_status": "PENDING",
"withdrawal_amount": "10.00",
"settlement_currency": "USD",
"created_at": 1786582800,
"updated_at": 1786582800
}
],
"total": 1
}
}
按平台提现标识查询单笔详情:
GET /payment/vcc/withdrawals/{withdrawal_id}
权限:payment.vcc.read。响应返回 data.withdrawal,字段与提交接口中的 withdrawal 相同;不存在或不属于当前商户账户的提现返回 404 CARD_WITHDRAWAL_NOT_FOUND。
查询接口返回当前状态;Webhook 用于异步通知状态变化,收到通知后可用详情接口再次确认。
11. 冻结和解冻#
11.1 冻结卡片#
POST /payment/vcc/cards/{card_id}/freeze
权限:payment.vcc.card.status
Path 参数 card_id 指定卡片。请求体的 request_id 为必填字符串,用于保证本次状态变更请求幂等。
响应包含 data.request_id、data.card_id 和 data.resource_status;resource_status 为 PENDING、SUCCESS 或 FAIL。
11.2 解冻卡片#
POST /payment/vcc/cards/{card_id}/unfreeze
权限:payment.vcc.card.status
Path 参数和请求体与冻结接口相同。每次新的解冻业务请求使用新的 request_id。响应包含 request_id、card_id 和 resource_status。
卡片当前状态通过卡片详情的 card_status 或 vcc.card.updated 事件取得。
12. 交易#
12.1 对外交易模型#
vcc.transaction.updated 最终只向商户推送以下四种交易类型:
transaction_type |
说明 | 是否关联原交易 |
|---|---|---|
auth |
消费授权账单。授权、结算和消费失败都更新同一笔账单,不单独暴露结算类型 | 否 |
void |
结算前撤销或授权释放 | 是,通过 original_transaction_id |
refund |
结算后退款 | 是,通过 original_transaction_id |
fee |
独立费用交易,仅在卡管理费或 3DS 费成功扣收后生成;其他费用不单独生成 fee 交易 |
否 |
交易状态只使用:
transaction_status |
说明 |
|---|---|
authorized |
已授权、尚未完成最终结算 |
failed |
当前交易处理失败;如上游后续纠正为成功,仍可能收到 succeed 更新 |
succeed |
交易已完成,不应被较早的 authorized 或 failed 通知回退 |
典型消费状态流为 auth / authorized → auth / succeed 或 auth / failed。结算成功时沿用原 transaction_id,只更新状态、结算金额和费用总额。
交易查询对象的主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
transaction_id |
string | 平台稳定的商户交易标识;同一消费从授权到结算保持不变 |
card_id |
string | 平台卡片标识 |
card_last4 |
string | 卡号后四位;有安全脱敏卡号时返回 |
product_code |
string | 产品代码 |
three_ds_id |
string | 独立 3DS 费关联的挑战标识;其他交易省略 |
deduction_source |
string | 费用实际扣款来源:card 或 merchant_wallet;其他交易省略 |
transaction_type |
string | auth、void、refund 或 fee |
transaction_status |
string | authorized、failed 或 succeed |
fee_type |
string | 独立卡管理费返回 card_management,独立 3DS 费返回 three_ds;其他交易省略 |
transaction_amount |
string | 刷卡或业务原始金额,固定两位小数 |
transaction_currency |
string | 刷卡或业务原始币种 |
authorization_amount |
string | 平台最终授权金额,固定两位小数 |
authorization_currency |
string | 授权币种 |
fee_amount |
string | 商户可见的已确认费用汇总,固定两位小数;独立费用为 0.00 |
fee_currency |
string | 费用总额币种,当前为 USDT |
settlement_amount |
string | 平台最终结算/实际扣款金额,固定两位小数;授权阶段通常为 0.00,结算完成后更新为最终值 |
settlement_currency |
string | 结算币种;可能与刷卡币种不同 |
merchant_name |
string | 商户名称 |
merchant_descriptor |
string | 账单商户描述 |
merchant_country |
string | 商户国家或地区代码 |
merchant_category_code |
string | 商户类别代码 |
original_transaction_id |
string | 撤销或退款所关联的原消费交易标识;不适用时为空 |
occurred_at |
integer | 交易时间,Unix 秒 |
fee_amount 为本笔交易返回的商户可见费用汇总。未配置或不适用的费用不会计入;商户接口和 Webhook 不返回费用拆分。
结算完成后请直接使用 settlement_amount 作为最终实际扣款金额;fee_amount 仅用于展示费用汇总,不要根据其他金额字段自行重算或重复相加。金额以平台返回的最终交易快照为准。
独立卡管理费使用 fee_type = card_management;扣款成功的 3DS 费使用 fee_type = three_ds。两者都使用 transaction_type = fee,应收金额放在 transaction_amount 和 settlement_amount,fee_amount 为 0.00,避免重复计算。3DS 扣费失败或结果未知时只保留费用业务任务,不生成成功交易;补偿成功后才出现该笔交易。
12.2 查询单卡交易#
GET /payment/vcc/cards/{card_id}/transactions
权限:payment.vcc.read
Path 参数 card_id 为必填。Query 参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
transaction_type |
string | 否 | auth、void、refund 或 fee;不区分大小写 |
transaction_status |
string | 否 | authorized、failed 或 succeed;不区分大小写 |
start_at |
integer | 否 | 最早交易时间,Unix 秒,包含边界 |
end_at |
integer | 否 | 最晚交易时间,Unix 秒,包含边界 |
limit / offset |
integer | 否 | 通用分页参数 |
响应的 data.transactions 为交易对象数组,data.total 为交易总数。
12.3 查询全部 VCC 交易#
GET /payment/vcc/transactions
权限:payment.vcc.read
Query 参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
transaction_id |
string | 否 | 按 Webhook 返回的商户可见交易标识筛选 |
card_id |
string | 否 | 按卡片标识筛选 |
product_code |
string | 否 | 按产品代码筛选 |
transaction_type |
string | 否 | auth、void、refund 或 fee;不区分大小写 |
transaction_status |
string | 否 | authorized、failed 或 succeed;不区分大小写 |
start_at |
integer | 否 | 最早交易时间,Unix 秒,包含边界 |
end_at |
integer | 否 | 最晚交易时间,Unix 秒,包含边界 |
limit / offset |
integer | 否 | 通用分页参数 |
响应的 data.transactions 为交易对象数组,字段含义见本章“交易对象的主要字段”;data.total 为交易总数。
查询结果是交易对账的最终依据。Webhook 和查询接口均使用 snake_case,共享字段保持同名。收到通知后应按 transaction_id 覆盖本地快照,并在需要对账时查询最新记录。
| 查询字段 | Webhook 字段 |
|---|---|
transaction_id |
data.transaction_id |
card_id |
data.card_id |
product_code |
data.product_code |
transaction_type |
data.transaction_type |
transaction_status |
data.transaction_status |
transaction_amount / transaction_currency |
data.transaction_amount / data.transaction_currency |
authorization_amount / authorization_currency |
data.authorization_amount / data.authorization_currency(平台最终授权金额和币种) |
settlement_amount / settlement_currency |
data.settlement_amount / data.settlement_currency(平台最终结算/实际扣款金额和币种) |
fee_amount / fee_currency |
data.fee_amount / data.fee_currency(商户可见费用汇总和币种,不返回费用明细) |
original_transaction_id |
data.original_transaction_id |
12.4 模拟交易(仅 Sandbox / 本地环境)#
POST /payment/vcc/transactions/simulate
此接口用于在不调用发卡行的情况下验证交易入账、卡余额变化、费用处理和 vcc.transaction.updated Webhook。接口仅在非生产环境开放;生产环境调用返回 403 CARD_TRANSACTION_SIMULATION_DISABLED。
接口仍要求正常的 Payment API Bearer Token,并按当前 API Key 的账户范围校验卡片归属,但不要求额外的业务权限。请求体:
请求无需提供 merchant_data。模拟器会自动使用固定测试商户 Local transaction simulation、MCC 5734、国家代码 US;HTTP 响应以平铺字段 merchant_name / merchant_category_code / merchant_country 返回,交易 Webhook 则放在 data.merchant_data.name / category_code / country 中。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 1–64 个字符的幂等标识;相同参数重放返回原交易,不同参数重用返回 IDEMPOTENCY_CONFLICT |
card_id |
string | 是 | 当前账户下状态为 ACTIVE 的卡片标识 |
original_transaction_id |
string | 否 | 结算、撤销或退款关联已有本地模拟账单时传入原交易标识;结算使用 AUTH 搭配该字段 |
transaction_type |
string | 是 | 统一账单动作:AUTH、VOID 或 REFUND;AUTH 不带原交易号创建授权,带原交易号完成结算;必须大写 |
amount |
string | 是 | 大于 0、最多两位小数的 USD 金额 |
模拟动作码(transaction_type) |
商户可见结果 | 本金或授权变化 | 费用展示 |
|---|---|---|---|
AUTH |
auth / authorized |
卡可用额度减少,授权占用增加 | 授权账单按当前产品配置评估普通费用并写入 fee_amount;不创建独立费用交易 |
AUTH(带 original_transaction_id) |
auth / succeed |
结算本金扣款并更新原 auth |
沿用原账单更新最终 fee_amount 和 settlement_amount;不创建独立结算或费用交易 |
VOID |
void / succeed |
释放尚未释放的本地模拟授权 | 适用撤销费写入该 void 账单的 fee_amount,不创建独立费用交易 |
REFUND |
refund / succeed |
退回尚未退回的本地模拟结算本金 | 适用退款费写入该 refund 账单的 fee_amount,不创建独立费用交易 |
费用不是模拟接口的请求动作。模拟接口仅用于验证账单生命周期;费用是否收取由当前卡产品配置决定,未配置或配置为 0 时不收取。普通消费最多发送两次交易 Webhook:授权时的 auth / authorized,以及结算时同一 transaction_id 的 auth / succeed;费用随交易账单快照返回,不会追加独立普通费用 Webhook。3DS 费用仅由真实 3DS 事件触发。
请求示例:
{
"request_id": "merchant-sim-A202608140001",
"card_id": "card_0123456789abcdef",
"transaction_type": "AUTH",
"amount": "10.00"
}
响应关键字段:
{
"data": {
"transaction": {
"transaction_id": "sim_auth_934dea33",
"transaction_type": "auth",
"transaction_status": "authorized",
"transaction_amount": "10.00",
"transaction_currency": "USD",
"authorization_amount": "10.00",
"authorization_currency": "USD",
"fee_amount": "0.00",
"fee_currency": "USDT",
"settlement_amount": "0.00",
"settlement_currency": "USD",
"merchant_name": "Local transaction simulation",
"merchant_descriptor": "Local transaction simulation",
"merchant_country": "US",
"merchant_category_code": "5734"
}
}
}
保存 sim_auth_934dea33,用于后续结算或撤销。
步骤 2A:把原授权结算为成功消费#
{
"request_id": "merchant-sim-C202608140002",
"card_id": "card_0123456789abcdef",
"original_transaction_id": "sim_auth_934dea33",
"transaction_type": "AUTH",
"amount": "10.00"
}
响应仍返回 transaction_id = sim_auth_934dea33,但状态变为 transaction_type = auth、transaction_status = succeed。平台为同一 data.transaction_id 发送第二次完整交易 Webhook,更新最终 fee_amount 和 settlement_amount,不产生独立结算账单或普通费用交易。未配置的费用不会收取。
步骤 2B:撤销尚未结算的授权#
这是步骤 2A 的替代分支,必须对另一笔仍为 authorized 的模拟授权调用:
{
"request_id": "merchant-sim-V202608140003",
"card_id": "card_0123456789abcdef",
"original_transaction_id": "sim_auth_another",
"transaction_type": "VOID",
"amount": "10.00"
}
响应生成一笔新的 void / succeed 交易,original_transaction_id = sim_auth_another。
步骤 3:对已结算消费退款#
{
"request_id": "merchant-sim-R202608140004",
"card_id": "card_0123456789abcdef",
"original_transaction_id": "sim_auth_934dea33",
"transaction_type": "REFUND",
"amount": "4.00"
}
响应生成一笔新的 refund / succeed 交易,original_transaction_id = sim_auth_934dea33,成功时 settlement_amount = 4.00。
成功响应的 data.transaction 始终使用本章的商户交易结构。VOID 金额不能超过可释放授权,REFUND 金额不能超过可退款本金;不满足条件时返回对应业务错误。模拟交易不会关联或改动发卡行真实交易。
模拟接口常见错误:
| HTTP | code |
说明 |
|---|---|---|
403 |
CARD_TRANSACTION_SIMULATION_DISABLED |
生产环境禁止调用 |
404 |
ORIGINAL_TRANSACTION_NOT_FOUND |
当前账户和卡片下找不到指定原模拟交易 |
409 |
ORIGINAL_TRANSACTION_INVALID |
原交易状态、类型或剩余金额不允许当前动作 |
409 |
CARD_STATUS_NOT_ALLOWED |
卡片不是可执行模拟交易的状态 |
422 |
INSUFFICIENT_CARD_BALANCE |
卡余额、可释放授权或可退款本金不足 |
主交易完全在平台本地入库并发送 vcc.transaction.updated Webhook。模拟本金会更新预付卡余额或共享卡额度;命中正费率时,费用事件仍进入正常费用处理、卡扣减和共享账户归集链路,因此该接口会真实改变测试环境的资金投影,不是只返回假响应的预览接口。
13. Webhook#
13.1 配置与订阅#
Webhook 配置包含:
- 公网 HTTPS 回调地址。
- Webhook Secret。
- VCC 事件订阅。
推荐订阅 vcc.*,等价于订阅以下六类事件:
vcc.application.updated
vcc.card.updated
vcc.topup.updated
vcc.withdrawal.updated
vcc.transaction.updated
vcc.3ds.required
创建或轮换 Webhook 后,立即保存接口响应或 Portal 最终展示的 secret。该值是实际验签密钥;签名密钥不会在 Webhook 列表中再次返回,丢失后需要轮换。
13.2 事件目录#
| 事件类型 | 子类型 / 交易类型 | 触发结果 | 对账标识 |
|---|---|---|---|
vcc.application.updated |
KYC_REQUIRED |
申请等待完成活体 | application_id |
vcc.application.updated |
FUNDS_REQUIRED |
申请等待补充账户余额 | application_id |
vcc.application.updated |
CARD_READY |
卡片已进入可用状态 | application_id、card_id |
vcc.application.updated |
APPLICATION_FAILED |
开卡申请失败 | application_id |
vcc.card.updated |
CARD_FROZEN |
冻结成功 | card_id |
vcc.card.updated |
CARD_UNFROZEN |
解冻成功 | card_id |
vcc.card.updated |
CARD_FREEZE_FAILED |
冻结失败 | card_id |
vcc.card.updated |
CARD_UNFREEZE_FAILED |
解冻失败 | card_id |
vcc.topup.updated |
NORMAL_TOPUP |
主动充值状态变化 | topup_id |
vcc.withdrawal.updated |
CARD_WITHDRAWAL |
共享卡提现状态变化 | withdrawal_id、merchant_withdrawal_no |
vcc.transaction.updated |
data.transaction_type 为 auth、void、refund 或 fee |
交易新增或数据变化 | data.transaction_id、data.card_id |
vcc.3ds.required |
CHALLENGE_REQUIRED |
需要处理 3DS 验证码 | three_ds_id |
充值本金不会作为卡交易出现在 vcc.transaction.updated 中,主动充值状态只通过 vcc.topup.updated 和充值查询接口返回。独立费用交易当前展示卡管理费和扣款成功的 3DS 费。
13.3 请求头与验签#
VCC 的所有事件统一使用以下投递头部,不区分渠道或平台:Content-Type、X-Delivery-Id、X-Webhook-Event、X-Webhook-Id 和 X-Webhook-Signature。
| Header | 说明 |
|---|---|
Content-Type |
固定为 application/json |
X-Webhook-Signature |
原始 Body 的 HMAC-SHA256 小写十六进制签名 |
X-Webhook-Id |
Webhook 配置 ID |
X-Delivery-Id |
本次投递记录 ID |
X-Webhook-Event |
event_type |
创建或轮换 Webhook 后,必须使用接口响应或 Portal 最终展示的 secret 验签;不要直接使用创建请求中提交的原始自定义 Secret。
签名计算:
expected_signature = hex(HMAC_SHA256(raw_request_body, webhook_secret))
处理顺序:
- 读取并保留 HTTP 原始 Body 字节。
- 不要先格式化、排序字段或重新序列化 JSON。
- 使用 Webhook Secret 计算 HMAC-SHA256。
- 将结果编码为小写十六进制字符串。
- 使用常量时间比较校验
X-Webhook-Signature。 - 验签失败返回非
2xx,不得更新业务状态。
13.4 事件字段#
所有 VCC 事件均使用 snake_case。交易事件保留独立的 data 安全快照结构,完整字段见 13.10。
| 字段 | 返回范围 | 说明 |
|---|---|---|
event_id |
所有事件 | 事件去重键;重试沿用同一值 |
event_type |
所有事件 | 事件大类 |
event_subtype |
非交易事件 | 具体状态或动作 |
event_version |
非交易事件 | 当前固定为 v1 |
account_id |
非交易事件 | 事件所属账户标识 |
product_code |
非交易事件 | 卡产品代码 |
request_id |
关联写请求的事件 | 写接口使用的幂等标识 |
application_id |
申请事件 | 开卡申请标识 |
customer_id |
CARD_READY |
客户标识 |
card_id |
卡、充值、提现、3DS、CARD_READY |
卡片标识 |
card_last4 |
3DS | 卡号后四位;可安全取得时返回 |
topup_id |
充值事件 | 充值标识 |
withdrawal_id |
提现事件 | 平台提现标识 |
merchant_withdrawal_no |
提现事件 | 商户提现订单号 |
withdrawal_amount / settlement_currency |
提现事件 | 提现金额和结算币种 |
three_ds_id |
3DS 事件 | 3DS 挑战标识 |
fee_transaction_id / fee_type |
3DS 事件 | 预计生成的独立费用交易标识和固定值 three_ds |
assessed_fee_amount / fee_currency |
3DS 事件 | 本次 3DS 费用评估金额和扣费币种;不代表已经扣款成功 |
resource_status |
申请、充值、提现、卡、3DS | 资源或动作状态 |
next_action |
KYC_REQUIRED、FUNDS_REQUIRED |
下一步动作 |
failure_code / failure_message |
失败事件 | 失败代码 / 信息 |
occurred_at |
所有事件 | 业务发生时间;交易事件为 RFC 3339,其他事件为 Unix 秒 |
3DS 事件包含 verification_code,并可包含交易金额、币种、商户名称、商户国家或地区和 MCC。fee_transaction_id 用于关联后续扣费成功的 vcc.transaction.updated;收到 3DS 事件本身不代表费用已扣除。
13.5 通知处理规则#
接收 HTTP 请求
-> 保留原始 Body
-> 验证 HMAC 签名
-> 解析 JSON
-> 按 X-Webhook-Event 选择事件合同
-> 交易事件校验 event_type、data.transaction_id 和 data.card_id;其他事件校验 event_type、event_subtype 和 account_id
-> 以 event_id 写入事件表(唯一键)
-> 重复事件直接返回 2xx
-> 交易事件按 data.transaction_id 幂等更新本地账单
-> 提现事件按 withdrawal_id 幂等更新 resource_status
-> 其他非 3DS 事件按资源 ID 查询平台当前状态
-> 在事务中更新本地业务状态
-> 安全持久化完成后返回 2xx
必须遵守:
- 只有事件已经安全持久化后才返回 HTTP
2xx。 - 同一
event_id可能多次投递,接收方必须幂等。 - 不保证事件按业务发生顺序到达。
- 非 3DS 资源以查询接口返回的当前状态为最终处理依据;Webhook 用于异步通知,提现收到通知后可再查询详情确认。
- 对包含
account_id的非交易事件,校验其是否属于当前接收系统的账户范围。 verification_code不得写入普通业务日志、错误信息或监控标签。
13.6 开卡申请事件示例#
13.6.1 需要活体:KYC_REQUIRED#
{
"event_id": "vcc_evt_0123456789abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "KYC_REQUIRED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"product_code": "1103",
"application_id": "app_0123456789abcdef",
"resource_status": "PENDING",
"next_action": {
"action_type": "COMPLETE_LIVENESS"
},
"occurred_at": 1784995200
}
13.6.2 需要补充余额:FUNDS_REQUIRED#
{
"event_id": "vcc_evt_0a23456789abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "FUNDS_REQUIRED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"product_code": "1103",
"application_id": "app_0123456789abcdef",
"resource_status": "PENDING",
"next_action": {
"action_type": "ADD_FUNDS",
"required_account_balance": "6.01",
"required_balance_currency": "USDT",
"expires_at": 1785254400
},
"occurred_at": 1784995300
}
13.6.3 卡片可用:CARD_READY#
{
"event_id": "vcc_evt_1234567890abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "CARD_READY",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"application_id": "app_0123456789abcdef",
"customer_id": "cus_0123456789abcdef",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"masked_card_number": "409636******2420",
"resource_status": "SUCCESS",
"occurred_at": 1784995500
}
13.6.4 申请失败:APPLICATION_FAILED#
{
"event_id": "vcc_evt_2345678901abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "APPLICATION_FAILED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"product_code": "1103",
"application_id": "app_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784995500
}
13.7 卡片事件示例#
13.7.1 冻结成功:CARD_FROZEN#
{
"event_id": "vcc_evt_3456789012abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_FROZEN",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-freeze-F202607280001",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "SUCCESS",
"occurred_at": 1784995800
}
13.7.2 解冻成功:CARD_UNFROZEN#
{
"event_id": "vcc_evt_3567890123abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_UNFROZEN",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-unfreeze-U202607280001",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "SUCCESS",
"occurred_at": 1784995900
}
13.7.3 冻结失败:CARD_FREEZE_FAILED#
{
"event_id": "vcc_evt_3678901234abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_FREEZE_FAILED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-freeze-F202607280002",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784996000
}
13.7.4 解冻失败:CARD_UNFREEZE_FAILED#
{
"event_id": "vcc_evt_3789012345abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_UNFREEZE_FAILED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-unfreeze-U202607280002",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784996100
}
冻结和解冻只发送 SUCCESS 或 FAIL 终态 Webhook,不发送 PENDING Webhook。实际卡状态通过卡片详情接口确认。
13.8 充值事件示例#
event_subtype 固定为 NORMAL_TOPUP,通过 resource_status 区分状态。
13.8.1 处理中#
{
"event_id": "vcc_evt_4567890123abcdef",
"event_type": "vcc.topup.updated",
"event_subtype": "NORMAL_TOPUP",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-topup-T202607280001",
"product_code": "1103",
"topup_id": "top_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"resource_status": "PENDING",
"occurred_at": 1784995700
}
13.8.2 成功#
{
"event_id": "vcc_evt_4678901234abcdef",
"event_type": "vcc.topup.updated",
"event_subtype": "NORMAL_TOPUP",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-topup-T202607280001",
"product_code": "1103",
"topup_id": "top_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"resource_status": "SUCCESS",
"occurred_at": 1784995800
}
13.8.3 失败#
{
"event_id": "vcc_evt_4789012345abcdef",
"event_type": "vcc.topup.updated",
"event_subtype": "NORMAL_TOPUP",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-topup-T202607280001",
"product_code": "1103",
"topup_id": "top_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784995800
}
13.9 共享卡提现事件示例#
event_subtype 固定为 CARD_WITHDRAWAL,resource_status 为 PENDING、SUCCESS 或 FAIL。以下为成功终态示例:
{
"event_id": "vcc_evt_5890123456abcdef",
"event_type": "vcc.withdrawal.updated",
"event_subtype": "CARD_WITHDRAWAL",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-withdrawal-W202608130001",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"withdrawal_id": "wd_0123456789abcdef",
"merchant_withdrawal_no": "WD202608130001",
"withdrawal_amount": "10.00",
"settlement_currency": "USD",
"resource_status": "SUCCESS",
"occurred_at": 1786582860
}
失败事件还包含 failure_code 和 failure_message。按 event_id 去重,并按 withdrawal_id 幂等更新;终态 SUCCESS 或 FAIL 不得被迟到的 PENDING 覆盖。
13.10 交易事件示例#
交易事件使用 snake_case,并在 data 中发送安全账单快照;不包含 event_version、account_id、费用拆分或平台资金日记账。data.card_id 和 data.product_code 在所有交易通知中稳定返回,3DS 独立费用还会返回实际扣款来源。完整字段如下:
| 字段 | 说明 |
|---|---|
event_id |
本次交易快照事件的去重键;同一次投递重试保持不变 |
event_type |
固定为 vcc.transaction.updated |
occurred_at |
该事件发生时间,RFC 3339 |
data.transaction_id |
稳定交易标识;同一消费授权到结算保持不变 |
data.card_id / data.product_code |
平台卡片标识和产品代码;所有交易通知均返回 |
data.card_last4 |
卡号后四位;可安全取得时返回 |
data.three_ds_id |
3DS 独立费用关联的挑战标识 |
data.deduction_source |
3DS 费实际扣款来源:card 或 merchant_wallet |
data.transaction_type |
auth、void、refund 或 fee |
data.fee_type |
独立卡管理费返回 card_management;独立 3DS 费返回 three_ds |
data.transaction_status |
authorized、failed 或 succeed |
data.transaction_amount / data.transaction_currency |
刷卡或业务原始金额和币种 |
data.authorization_amount / data.authorization_currency |
平台最终授权金额和授权币种 |
data.settlement_amount / data.settlement_currency |
结算金额和币种;授权阶段可为 0.00,后续可能更新 |
data.fee_amount / data.fee_currency |
关联费用总额和币种;只给总额,不拆分明细 |
data.original_transaction_id |
撤销或退款关联的原消费交易标识;不适用时省略 |
data.merchant_data |
商户名称、MCC、城市和国家或地区;无数据时省略 |
data.authorization_code |
授权码;无数据时省略 |
data.transaction_time |
交易时间,RFC 3339 |
data.updated_time |
当前账单快照更新时间,RFC 3339 |
不同业务步骤的展示规则:
| 步骤 | data.transaction_type |
data.transaction_status |
关键金额 | 交易关联 |
|---|---|---|---|---|
| 消费授权成功 | auth |
authorized |
settlement_amount 通常为 0.00;fee_amount 为授权账单当前已确认的适用普通费用总额 |
使用消费 transaction_id |
| 消费授权失败 | auth |
failed |
返回当前已知金额和费用 | 与授权请求同一 transaction_id |
| 消费结算成功 | auth |
succeed |
settlement_amount、settlement_currency 和 fee_amount 更新为当前最终值 |
沿用授权的 transaction_id,不新增结算账单或普通费用交易 |
| 授权撤销 | void |
succeed 或 failed |
授权和结算金额为 0.00;适用撤销费写入该 void 账单的 fee_amount |
新 transaction_id,并返回 original_transaction_id |
| 结算后退款 | refund |
succeed 或 failed |
成功时 settlement_amount 为退款金额;适用退款费写入该 refund 账单的 fee_amount |
新 transaction_id,并返回 original_transaction_id |
| 卡管理费 | fee |
succeed |
transaction_amount 和 settlement_amount 为卡管理费,fee_amount 为 0.00 |
fee_type = card_management |
| 3DS 费扣款成功 | fee |
succeed |
transaction_amount 和 settlement_amount 为 3DS 费,fee_amount 为 0.00 |
fee_type = three_ds,transaction_id 等于 3DS 事件的 fee_transaction_id |
消费授权通知示例(真实渠道回调样例):
下面的 ANTHROPIC* CLAUDE SUB 仅用于展示真实渠道可能返回的商户资料,不是本地模拟交易的返回值。模拟交易的 Webhook 必须使用 Local transaction simulation、MCC 5734、国家代码 US;嵌套位置仍是 data.merchant_data。
{
"event_id": "vcc_evt_6789012345abcdef",
"event_type": "vcc.transaction.updated",
"occurred_at": "2026-08-24T10:20:15Z",
"data": {
"transaction_id": "934dea33-6ee0-44a0-baf8-fb36b4d2fe6d",
"card_id": "card_0123456789abcdef",
"product_code": "1103",
"transaction_type": "auth",
"transaction_status": "authorized",
"transaction_amount": "16.20",
"transaction_currency": "GBP",
"authorization_amount": "22.57",
"authorization_currency": "USD",
"settlement_amount": "0.00",
"settlement_currency": "USD",
"fee_amount": "0.52",
"fee_currency": "USDT",
"merchant_data": {
"name": "ANTHROPIC* CLAUDE SUB",
"category_code": "5734",
"city": "SAN FRANCISCO",
"country": "US"
},
"authorization_code": "76U47U",
"transaction_time": "2026-08-24T10:20:15Z",
"updated_time": "2026-08-24T10:20:16Z"
}
}
结算后,平台会使用新的 event_id 再次推送完整快照,但 data.transaction_id 保持不变,例如:
本例仅展示结算后的最终账单快照。商户应直接使用返回的 settlement_amount 作为实际扣款金额,不要根据 authorization_amount 与 fee_amount 自行重算。
{
"event_id": "vcc_evt_7890123456abcdef",
"event_type": "vcc.transaction.updated",
"occurred_at": "2026-08-25T03:12:40Z",
"data": {
"transaction_id": "934dea33-6ee0-44a0-baf8-fb36b4d2fe6d",
"card_id": "card_0123456789abcdef",
"product_code": "1103",
"transaction_type": "auth",
"transaction_status": "succeed",
"transaction_amount": "16.20",
"transaction_currency": "GBP",
"authorization_amount": "22.57",
"authorization_currency": "USD",
"settlement_amount": "22.81",
"settlement_currency": "USD",
"fee_amount": "0.52",
"fee_currency": "USDT",
"merchant_data": {
"name": "ANTHROPIC* CLAUDE SUB",
"category_code": "5734",
"city": "SAN FRANCISCO",
"country": "US"
},
"authorization_code": "76U47U",
"transaction_time": "2026-08-24T10:20:15Z",
"updated_time": "2026-08-25T03:12:40Z"
}
}
接收方必须先按 event_id 去重,再按 data.transaction_id 覆盖本地交易快照。交易发生实际变化时会生成新的 event_id,投递重试则沿用原 event_id。通知不保证顺序;不要让迟到的 authorized 覆盖 failed 或 succeed,也不要让 failed 覆盖已存在的 succeed。如状态或金额存在冲突,以交易查询接口的最新结果为准。
13.11 3DS 事件示例#
{
"event_id": "vcc_evt_7890123456abcdef",
"event_type": "vcc.3ds.required",
"event_subtype": "CHALLENGE_REQUIRED",
"event_version": "v1",
"account_id": "acct_example",
"product_code": "1103",
"three_ds_id": "3ds_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"card_last4": "4242",
"resource_status": "REQUIRED",
"verification_code": "123456",
"transaction_amount": "88.00",
"transaction_currency": "USD",
"merchant_name": "Example Store",
"merchant_country": "SG",
"merchant_category_code": "5411",
"fee_transaction_id": "txn_fee_3ds_fee_0123456789abcdef",
"fee_type": "three_ds",
"assessed_fee_amount": "0.37",
"fee_currency": "USDT",
"occurred_at": 1784995900
}
verification_code 按当前契约直接返回,不做 RSA 加密。必须先完成 HMAC-SHA256 验签,再读取和处理验证码。assessed_fee_amount 只是计费快照,不是扣款结果。
当卡余额扣款或商户钱包兜底扣款真正成功后,平台使用同一个 fee_transaction_id 发送独立费用交易:
{
"event_id": "vcc_evt_89abcdef01234567",
"event_type": "vcc.transaction.updated",
"occurred_at": "2026-08-24T12:00:02Z",
"data": {
"transaction_id": "txn_fee_3ds_fee_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"card_last4": "4242",
"product_code": "1103",
"three_ds_id": "3ds_0123456789abcdef",
"deduction_source": "card",
"transaction_type": "fee",
"fee_type": "three_ds",
"transaction_status": "succeed",
"transaction_amount": "0.37",
"transaction_currency": "USDT",
"authorization_amount": "0.00",
"authorization_currency": "USDT",
"settlement_amount": "0.37",
"settlement_currency": "USDT",
"fee_amount": "0.00",
"fee_currency": "USDT",
"merchant_data": {"name": "Example Store"},
"transaction_time": "2026-08-24T12:00:02Z",
"updated_time": "2026-08-24T12:00:02Z"
}
}
扣费失败或结果未知时不会伪造 succeed 交易通知;费用留在业务任务中,待系统重试或后台从失败步骤继续。补偿成功后才发送上面的交易事件。
13.12 响应、重试和乱序规则#
| 规则 | 当前行为 |
|---|---|
| 成功确认 | 接收方返回任意 HTTP 2xx |
| 首次投递 | 事件生成后立即投递 |
| 最大投递次数 | 首次 1 次,加失败重试最多 9 次;总计最多 10 次 |
| 默认重试间隔 | 1、2、5、10、20、40、80、240、1020 分钟 |
| 默认累计窗口 | 约 23 小时 38 分钟,实际时间可能有少量偏差 |
| 自定义计划上限 | 72 小时硬上限;不表示默认计划持续 72 小时 |
| 重复投递 | 同一事件重试沿用同一 event_id;必须幂等处理 |
| 到达顺序 | 不保证按业务发生顺序到达 |
| 状态确认 | 交易、共享卡提现及其他有查询接口的资源以查询结果为准;3DS 按对应事件规则处理 |
网络超时、连接失败或非 2xx 响应按失败投递处理,并进入重试计划。不要在业务处理完成前提前返回 2xx。
14. 接口总表#
| # | 方法 | 路径 | API Reference |
|---|---|---|---|
| 1 | GET |
/payment/account |
查看 |
| 2 | GET |
/payment/balances |
查看 |
| 3 | GET |
/payment/deposits |
查看 |
| 4 | GET |
/payment/ledger |
查看 |
| 5 | GET |
/payment/vcc/products |
查看 |
| 6 | POST |
/payment/vcc/files |
查看 |
| 7 | POST |
/payment/vcc/customers |
查看 |
| 8 | GET |
/payment/vcc/customers |
查看 |
| 9 | GET |
/payment/vcc/customers/{customer_id} |
查看 |
| 10 | PATCH |
/payment/vcc/customers/{customer_id} |
查看 |
| 11 | POST |
/payment/vcc/card-applications |
查看 |
| 12 | GET |
/payment/vcc/card-applications |
查看 |
| 13 | GET |
/payment/vcc/card-applications/{application_id} |
查看 |
| 14 | GET |
/payment/vcc/cards |
查看 |
| 15 | GET |
/payment/vcc/cards/{card_id} |
查看 |
| 16 | POST |
/payment/vcc/cards/sensitive |
查看 |
| 17 | GET |
/payment/vcc/cards/{card_id}/balance |
查看 |
| 18 | POST |
/payment/vcc/cards/{card_id}/topups |
查看 |
| 19 | GET |
/payment/vcc/topups |
查看 |
| 20 | GET |
/payment/vcc/topups/{topup_id} |
查看 |
| 21 | POST |
/payment/vcc/cards/{card_id}/withdrawals |
查看 |
| 22 | GET |
/payment/vcc/withdrawals |
查看 |
| 23 | GET |
/payment/vcc/withdrawals/{withdrawal_id} |
查看 |
| 24 | POST |
/payment/vcc/cards/{card_id}/freeze |
查看 |
| 25 | POST |
/payment/vcc/cards/{card_id}/unfreeze |
查看 |
| 26 | GET |
/payment/vcc/cards/{card_id}/transactions |
查看 |
| 27 | GET |
/payment/vcc/transactions |
查看 |
| 28 | POST |
/payment/vcc/transactions/simulate |
查看 |
15. 超时与重试#
GET 请求可直接重试。
POST 或 PATCH 请求超时后,使用原 request_id 和原请求参数重试。已经取得资源 ID 时,使用对应查询接口读取当前状态;共享卡提现可用 GET /payment/vcc/withdrawals/{withdrawal_id} 查询,或使用提现列表按商户提现单号检索。Webhook 到达后可再查询详情确认。