开放 API 文档

等待填写测试配置

接入说明

重要提示

请注意代码逻辑和请求频率,如需频繁请求请联系客服。接口同步响应仅表示请求受理或当前处理状态,最终业务结果以 Webhook 推送结果为准。

商户开通开放 API 后,可以使用 API Key / API Secret 调用 VCC 提供的开放业务接口。后台或商户端登录态接口不属于开放 API,不在本文档中列出。

21当前已开放业务接口
HMAC统一签名方式
POST当前接口统一使用 POST 测试

调用前准备

  • 登录商户端后,点击右上角头像,再点击「开发者配置」,生成 API Key 和 API Secret。
  • API Secret 明文只展示一次,请妥善保存。
  • 正式环境可按需配置公网 IPv4 白名单;未配置时不限制来源 IP,配置后仅允许白名单 IP 调用。
  • 请求和响应正文统一使用 JSON。

鉴权 Header

Header必填说明
X-VCC-API-KEY是商户 API Key。
X-VCC-TIMESTAMP是毫秒时间戳。
X-VCC-NONCE是随机字符串,建议每次请求唯一。
X-VCC-SIGNATURE是请求签名,使用 API Secret 计算。
X-VCC-REQUEST-ID否商户侧请求 ID,不传时服务端生成。

签名原文

HTTP_METHOD + "\n" +
REQUEST_PATH + "\n" +
TIMESTAMP + "\n" +
NONCE + "\n" +
SHA256_HEX(RAW_REQUEST_BODY)

在线测试会自动计算签名,并在调试信息中显示签名原文、bodyHash 和 signature。

Webhook 总览

Webhook 是 VCC 主动向商户推送本地业务已收口事件的能力。VCC 不直接转发上游原始回调;开卡、卡操作、卡交易、3DS 验证码和预算操作在本地业务处理完成后写入 outbox,再异步向商户配置的 Webhook 地址发起 POST 推送。

  • 投递语义为至少一次,商户侧必须做幂等处理。
  • Webhook 地址保存时会校验 URL 格式和公网地址;投递前还会再次校验,防止域名后续改指内网地址。
  • Webhook Secret 明文只在生成或重置时展示一次,保存后不再回显。
  • 3DS 验证码属于敏感信息,只有显式订阅 CARD_3DS 的商户才会收到。

成功判定与重试策略

VCC 按商户 Webhook 接口的 HTTP 状态码和响应正文共同判断本次推送是否成功:商户接口必须返回 2xx,且响应正文去除首尾空白后等于 ok(大小写不敏感),才表示已接收成功。其他 HTTP 状态码、2xx 但正文不是 ok、网络异常、超时、DNS 或 URL 安全校验失败,都视为本次推送失败。

投递次数触发时机说明
第 1 次事件创建后尽快异步推送业务事件写入 outbox 后立即尝试投递。
第 2 次第 1 次失败约 1 分钟后仅在首次未返回 ok 或发生异常时触发。
第 3 次上次失败约 5 分钟后仍失败则继续等待下一轮。
第 4 次上次失败约 15 分钟后按到期时间由定时任务扫描推送。
第 5 次上次失败约 30 分钟后HTTP 3xx/4xx/5xx 都不会视为成功。
第 6 次上次失败约 1 小时后商户侧应保证接口稳定返回 ok。
第 7 次上次失败约 3 小时后最后一次重试;仍失败则标记为放弃。

重试任务默认每 30 秒扫描一次已到重试时间的失败记录,因此实际投递时间可能比表中时间略有延迟。商户侧收到重复事件时,应使用 eventId 做接收幂等。

Webhook 请求 Header

Header说明
X-VCC-WEBHOOK-IDWebhook 事件 ID,对应正文 eventId。
X-VCC-WEBHOOK-EVENTWebhook 精确事件类型,对应正文 eventType。
X-VCC-WEBHOOK-TIMESTAMPVCC 发送时间戳,毫秒。
X-VCC-WEBHOOK-NONCE本次推送随机串。
X-VCC-WEBHOOK-SIGNATURE签名值,格式为 v1=hex。

签名原文

eventId + "\n" +
eventType + "\n" +
timestamp + "\n" +
nonce + "\n" +
SHA256_HEX(RAW_REQUEST_BODY)

签名算法为 HMAC-SHA256,密钥使用商户配置的 Webhook Secret。商户侧收到推送后,应取原始请求 body 计算 SHA256,再按上方原文拼接并校验 X-VCC-WEBHOOK-SIGNATURE。

外层字段

字段类型说明
eventIdString本次 Webhook 事件唯一 ID。商户侧可用该字段做接收幂等。
eventTypeString精确事件类型,例如 CARD_TRANSACTION.SETTLED、BUDGET_OPERATION.RECHARGE_SUCCESS。建议商户按该字段分发业务。
eventCategoryString事件大类,例如 CARD_TRANSACTION、BUDGET_OPERATION。用于粗粒度分组和订阅。
eventTimeStringVCC 生成事件时间,格式 yyyy-MM-dd HH:mm:ss。
apiVersionStringWebhook 契约版本,当前为 2026-06-01。
merchantIdNumber商户 ID。
dataObject业务数据。不同 eventType 下字段不同。

订阅大类和事件

大类事件说明
CARD_ISSUECARD_ISSUE.SUCCESS
CARD_ISSUE.FAILED
开卡成功、确认失败且已退款。
CARD_OPERATIONCARD_OPERATION.RECHARGE_SUCCESS
CARD_OPERATION.WITHDRAW_SUCCESS
CARD_OPERATION.FREEZE_SUCCESS
CARD_OPERATION.UNFREEZE_SUCCESS
CARD_OPERATION.CANCEL_SUCCESS
CARD.RISK_CANCELLED
CARD_OPERATION.LIMIT_CHANGE_SUCCESS
CARD_OPERATION.REMARK_UPDATE_SUCCESS
卡充值、余额转出、冻结、解冻、销卡、单卡限额变更、卡备注变更。
CARD_TRANSACTIONCARD_TRANSACTION.PROCESSING
CARD_TRANSACTION.AUTH_SUCCESS
CARD_TRANSACTION.AUTH_FAILED
CARD_TRANSACTION.SETTLED
CARD_TRANSACTION.REFUND_SUCCESS
CARD_TRANSACTION.REVERSE_SUCCESS
CARD_TRANSACTION.CORRECTION
交易授权、失败、清算、退款、撤销和订单修正。
CARD_3DSCARD_3DS.OTP_RECEIVED3DS 验证码到达通知;仅显式订阅后推送。
BUDGET_OPERATIONBUDGET_OPERATION.CREATED
BUDGET_OPERATION.RECHARGE_SUCCESS
BUDGET_OPERATION.WITHDRAW_SUCCESS
预算组创建、充值成功、转出成功。

幂等建议

  • 接收层幂等:使用 eventId 防止同一 Webhook 重试导致重复处理。
  • 交易业务幂等:同一订单可能按阶段推送多次,建议按 data.transactionId + eventType 记录事件,并用 data.transactionId 推进本地状态机。
  • 卡操作和预算操作按 eventId 做接收幂等;销卡与延迟到账可能分别通知,须同时接收销卡与余额转出事件。

开卡事件

开卡成功后推送 CARD_ISSUE.SUCCESS。该事件表示 VCC 已完成本地开卡结果收口,并返回商户可用的卡交付信息。

CARD_ISSUE.SUCCESS 示例

{
  "eventId": "card_issue_901_SUCCESS",
  "eventType": "CARD_ISSUE.SUCCESS",
  "eventCategory": "CARD_ISSUE",
  "eventTime": "2026-07-02 11:30:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "taskId": 901,
    "batchNo": "BATCH202607020001",
    "requestNo": "kaika_412321_idsjaidja",
    "cardType": "PREPAID",
    "budgetId": null,
    "cardGroupId": null,
    "applyStatus": "SUCCESS",
    "fundStatus": "CONFIRMED",
    "totalCount": 1,
    "successCount": 1,
    "failCount": 0,
    "cards": [
      {
        "cardId": "VC202607020001",
        "cardNoMask": "486532******1298",
        "cardType": "PREPAID",
        "cardStatus": 1,
        "remark": "广告投放卡",
        "effectiveLimitConfig": {
          "perTransLimit": "0.00",
          "dayLimit": "0.00",
          "monthLimit": "0.00",
          "cardLifeCycleLimit": "3000.00",
          "currency": "USD"
        },
        "cardNumberCiphertext": "base64url_iv_ciphertext_tag",
        "expiryDateCiphertext": "base64url_iv_ciphertext_tag",
        "cvvCiphertext": "base64url_iv_ciphertext_tag",
        "sensitiveEncryptAlg": "AES-256-GCM",
        "sensitiveEncryptVersion": "v1",
        "issueBatchNo": "BATCH202607020001",
        "createdAt": "2026-07-02 11:29:58"
      }
    ],
    "failItems": [],
    "completeTime": "2026-07-02 11:30:00",
    "updateTime": "2026-07-02 11:30:00"
  }
}

CARD_ISSUE.FAILED 示例

{
  "eventId": "card_issue_902_FAILED",
  "eventType": "CARD_ISSUE.FAILED",
  "eventCategory": "CARD_ISSUE",
  "eventTime": "2026-07-02 11:45:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "taskId": 902,
    "batchNo": "BATCH202607020002",
    "requestNo": "kaika_412321_failed01",
    "cardType": "PREPAID",
    "budgetId": null,
    "cardGroupId": null,
    "applyStatus": "FAILED",
    "fundStatus": "REFUNDED",
    "totalCount": 1,
    "successCount": 0,
    "failCount": 1,
    "cards": [],
    "failItems": [
      {
        "itemId": 8891,
        "itemNo": "BATCH202607020002-0001",
        "seqNo": 1,
        "status": "FAILED",
        "taskStatus": "FAILED",
        "fundStatus": "REFUNDED",
        "failReasonCode": "CARD_ISSUE_FAILED",
        "failReasonText": "开卡失败,已退款"
      }
    ],
    "completeTime": "2026-07-02 11:45:00",
    "updateTime": "2026-07-02 11:45:00"
  }
}

三要素解密

开卡成功 Webhook 中完整卡号、有效期和 CVV 只以密文返回。商户必须先配置 Webhook Secret;未配置 Secret 时无法启用 Webhook。解密密钥使用 Webhook Secret 派生,不使用 API Key 或 API Secret。

key = HMAC-SHA256(webhookSecret, "vcc-webhook-sensitive-v1")
plain = AES-256-GCM-Decrypt(
  key,
  base64url_decode(ciphertext)[0..11],       // 12 字节 IV
  base64url_decode(ciphertext)[12..end]      // ciphertext + 16 字节 tag
)

密文字段格式为 base64url(iv + ciphertext + tag),不包含 = 填充。sensitiveEncryptAlg 当前固定为 AES-256-GCM,sensitiveEncryptVersion 当前固定为 v1。

data 字段说明

字段说明
taskId开卡申请任务 ID。
batchNo开卡批次号,可用于查询本批卡。
requestNo商户自定义开卡请求号,VCC 会在开卡同步响应、状态查询和开卡终态 Webhook 中原样返回。
applyStatus本次申请最终业务状态。Webhook 当前只推送明确终态 SUCCESS 或 FAILED。
fundStatus资金状态。失败 Webhook 只在 REFUNDED 后发送;人工核对或可能补出卡的失败不会推送 CARD_ISSUE.FAILED。
cards成功开出的卡列表,包含 VCC 卡 ID、脱敏卡号、卡类型、卡状态、卡备注 remark、当前生效限额 effectiveLimitConfig、完整卡号密文 cardNumberCiphertext、有效期密文 expiryDateCiphertext、CVV 密文 cvvCiphertext 和批次号。
failItems确认失败且已收口的明细列表,失败原因仅返回商户可见业务文案。

卡操作事件

卡操作事件统一归入 CARD_OPERATION。充值和余额转出带金额;冻结、解冻、销卡、单卡限额变更、卡备注变更均表达本地业务已收口后的操作结果。

普通销卡推送 CARD_OPERATION.CANCEL_SUCCESS;风控销卡推送 CARD.RISK_CANCELLED,订阅 CARD_OPERATION 即可接收。两类事件均保留 refundAmount 和 refundCurrency。启用新的销卡通知规则后,通常从本地确认销卡起设置 60 秒退款合并窗口:实际到账则一起推送,金额填实际到账值(例如 0.01);窗口到期后检查仍未到账,则先发销卡成功、金额填 0.00,到账后另发 CARD_OPERATION.WITHDRAW_SUCCESS。明确无需退款、已知延迟退款或需人工核对时立即发零金额销卡通知。0.00 只表示本条未包含退款,不代表后续没有退款。

销卡退款通知接收规则

  • 合并通知:销卡成功中已包含正金额退款时,同一笔退款不再另发余额转出,避免重复记账。
  • 拆分通知:先接收 refundAmount=0.00 的销卡成功,到账后按转出事件的 amount / currency 记账。
  • 仅订阅 CANCEL_SUCCESS 不会自动收到转出;请订阅 CARD_OPERATION,或同时订阅所需销卡事件和 CARD_OPERATION.WITHDRAW_SUCCESS。
  • 在新规则生效范围内,首次配置 Webhook 之前已发生的销卡和已到账退款,不因首次配置补推;配置之后新到账的销卡退款仍可按转出订阅独立通知。
  • 重复投递以 eventId 幂等;退款转出事件 ID 为 card_operation_cancel_refund_<账户流水ID>_WITHDRAW_SUCCESS。网络重试可能导致乱序,不以接收顺序推断卡状态。
  • 60 秒是正常流程的合并窗口,不保证一分钟内送达。定时扫描可能稍晚;若通知尚未生成且退款已到账,可合并推送。重启恢复或已知延迟退款等场景可能提前拆分,请始终兼容“销卡零金额 + 后续转出”。历史已生成通知保持原 JSON,不因新规则自动重推。

充值成功示例

{
  "eventId": "wh_202607020101",
  "eventType": "CARD_OPERATION.RECHARGE_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 11:35:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "CR202607020001",
    "operationType": "RECHARGE",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "amount": "200.00",
    "currency": "USD",
    "operationTime": "2026-07-02 11:34:58"
  }
}

余额转出成功示例

{
  "eventId": "wh_202607020102",
  "eventType": "CARD_OPERATION.WITHDRAW_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 11:40:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "CW202607020001",
    "operationType": "WITHDRAW",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "amount": "50.00",
    "currency": "USD",
    "operationTime": "2026-07-02 11:39:59"
  }
}

冻结成功示例

{
  "eventId": "wh_202607020103",
  "eventType": "CARD_OPERATION.FREEZE_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 11:45:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "CF202607020001",
    "operationType": "FREEZE",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "operationTime": "2026-07-02 11:44:59"
  }
}

解冻成功示例

{
  "eventId": "wh_202607020104",
  "eventType": "CARD_OPERATION.UNFREEZE_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 11:50:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "CU202607020001",
    "operationType": "UNFREEZE",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "operationTime": "2026-07-02 11:49:59"
  }
}

销卡成功示例

{
  "eventId": "wh_202607020105",
  "eventType": "CARD_OPERATION.CANCEL_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 11:55:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "CC202607020001",
    "operationType": "CANCEL",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "refundAmount": "0.00",
    "refundCurrency": "USD",
    "operationTime": "2026-07-02 11:54:59"
  }
}

储值卡销卡合并退款示例

本条已包含实际到账的 0.01 USD,同一笔退款不再另发余额转出通知。

{
  "eventId": "card_operation_card_operation_3002_CANCEL_SUCCESS",
  "eventType": "CARD_OPERATION.CANCEL_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-08-28 12:00:20",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "cancel_example_3002",
    "operationType": "CANCEL",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "PREPAID",
    "refundAmount": "0.01",
    "refundCurrency": "USD",
    "operationTime": "2026-08-28 12:00:00"
  }
}

风控销卡成功示例

{
  "eventId": "card_operation_card_operation_3001_RISK_CANCELLED",
  "eventType": "CARD.RISK_CANCELLED",
  "eventCategory": "CARD",
  "eventTime": "2026-07-21 10:45:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "agg_tx_risk_001",
    "operationType": "CANCEL",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "PREPAID",
    "cancelType": "RISK_CANCEL",
    "reason": "风控销卡",
    "sourceTransactionId": "agg_tx_risk_001",
    "refundAmount": "3.80",
    "refundCurrency": "USD",
    "operationTime": "2026-07-21 10:44:59"
  }
}

单卡限额变更成功示例

{
  "eventId": "card_operation_card_limit_change_8812_LIMIT_CHANGE_SUCCESS",
  "eventType": "CARD_OPERATION.LIMIT_CHANGE_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 12:05:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "CL202607020001",
    "operationType": "LIMIT_CHANGE",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "beforeLimitConfig": {
      "perTransLimit": "0.00",
      "dayLimit": "0.00",
      "monthLimit": "0.00",
      "cardLifeCycleLimit": "2000.00",
      "currency": "USD"
    },
    "afterLimitConfig": {
      "perTransLimit": "0.00",
      "dayLimit": "0.00",
      "monthLimit": "0.00",
      "cardLifeCycleLimit": "3000.00",
      "currency": "USD"
    },
    "currency": "USD",
    "remark": "调整广告卡生命周期限额",
    "operationTime": "2026-07-02 12:04:59"
  }
}

卡备注变更成功示例

{
  "eventId": "card_operation_card_operation_5424_REMARK_UPDATE_SUCCESS",
  "eventType": "CARD_OPERATION.REMARK_UPDATE_SUCCESS",
  "eventCategory": "CARD_OPERATION",
  "eventTime": "2026-07-02 12:10:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "requestNo": "RM202607020001",
    "operationType": "REMARK_UPDATE",
    "operationStatus": "SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "beforeRemark": "广告投放卡",
    "afterRemark": "广告投放卡-7月",
    "remark": "广告投放卡-7月",
    "operationTime": "2026-07-02 12:09:59"
  }
}

字段说明

字段说明
requestNo业务请求号或操作订单号。
operationTypeRECHARGE、WITHDRAW、FREEZE、UNFREEZE、CANCEL、LIMIT_CHANGE、REMARK_UPDATE。
amount资金变动金额,仅充值和余额转出类事件返回。
refundAmount / refundCurrency本条销卡通知一并确认的实际到账金额与币种;保留 0.00、0.01 等值。0.00 表示本条未包含退款;后续仍可能收到余额转出成功通知。
cancelType / reason / sourceTransactionId仅 CARD.RISK_CANCELLED 返回,用于说明风控销卡类型、商户可见原因和触发交易流水。
beforeLimitConfig / afterLimitConfig限额变更前后配置,仅 LIMIT_CHANGE 返回。
beforeRemark / afterRemark备注变更前后内容,仅 REMARK_UPDATE 返回。

卡交易事件

卡交易可能按阶段推送多次。同一订单可能先有处理中或授权成功,后续再有清算完成;撤销也可能先进入处理中,后续再推送撤销成功。商户侧应把 Webhook 当成状态推进事件,而不是一次性最终结果。

处理中示例

{
  "eventId": "wh_202607020200",
  "eventType": "CARD_TRANSACTION.PROCESSING",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:00:05",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900000",
    "relatedTransactionId": "",
    "eventStatus": "PROCESSING",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "PURCHASE",
    "originalAmount": "35.60",
    "originalCurrency": "USD",
    "actualAmount": "0.00",
    "actualCurrency": "USD",
    "feeAmount": "0.00",
    "merchantName": "Google Ads",
    "merchantCountry": "US",
    "merchantMcc": "7311",
    "transactionTime": "2026-07-02 12:00:02"
  }
}

授权成功示例

{
  "eventId": "wh_202607020201",
  "eventType": "CARD_TRANSACTION.AUTH_SUCCESS",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:01:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900001",
    "relatedTransactionId": "",
    "eventStatus": "AUTH_SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "PURCHASE",
    "originalAmount": "35.60",
    "originalCurrency": "USD",
    "actualAmount": "36.13",
    "actualCurrency": "USD",
    "feeAmount": "0.53",
    "merchantName": "Google Ads",
    "merchantCountry": "US",
    "merchantMcc": "7311",
    "transactionTime": "2026-07-02 12:00:02"
  }
}

授权失败示例

{
  "eventId": "wh_202607020202",
  "eventType": "CARD_TRANSACTION.AUTH_FAILED",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:03:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900002",
    "relatedTransactionId": "",
    "eventStatus": "AUTH_FAILED",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "PURCHASE",
    "originalAmount": "12.00",
    "originalCurrency": "USD",
    "actualAmount": "0.00",
    "actualCurrency": "USD",
    "feeAmount": "0.00",
    "merchantName": "Example Store",
    "merchantCountry": "US",
    "merchantMcc": "5812",
    "transactionTime": "2026-07-02 12:02:55"
  }
}

清算完成示例

{
  "eventId": "wh_202607020203",
  "eventType": "CARD_TRANSACTION.SETTLED",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:05:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900001",
    "relatedTransactionId": "",
    "eventStatus": "SETTLED",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "PURCHASE",
    "originalAmount": "35.60",
    "originalCurrency": "USD",
    "actualAmount": "36.13",
    "actualCurrency": "USD",
    "feeAmount": "0.53",
    "merchantName": "Google Ads",
    "merchantCountry": "US",
    "merchantMcc": "7311",
    "transactionTime": "2026-07-02 12:00:02"
  }
}

退款成功示例

{
  "eventId": "wh_202607020204",
  "eventType": "CARD_TRANSACTION.REFUND_SUCCESS",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:15:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900004",
    "relatedTransactionId": "txn_900001",
    "eventStatus": "REFUND_SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "REFUND",
    "originalAmount": "10.00",
    "originalCurrency": "USD",
    "actualAmount": "10.00",
    "actualCurrency": "USD",
    "feeAmount": "0.00",
    "merchantName": "Google Ads",
    "merchantCountry": "US",
    "merchantMcc": "7311",
    "transactionTime": "2026-07-02 12:14:58"
  }
}

撤销成功示例

{
  "eventId": "wh_202607020205",
  "eventType": "CARD_TRANSACTION.REVERSE_SUCCESS",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:20:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900005",
    "relatedTransactionId": "txn_900001",
    "eventStatus": "REVERSE_SUCCESS",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "REVERSE",
    "originalAmount": "35.60",
    "originalCurrency": "USD",
    "actualAmount": "35.60",
    "actualCurrency": "USD",
    "feeAmount": "0.00",
    "merchantName": "Google Ads",
    "merchantCountry": "US",
    "merchantMcc": "7311",
    "transactionTime": "2026-07-02 12:18:10"
  }
}

订单修正示例

{
  "eventId": "wh_202607020206",
  "eventType": "CARD_TRANSACTION.CORRECTION",
  "eventCategory": "CARD_TRANSACTION",
  "eventTime": "2026-07-02 12:25:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "transactionId": "txn_900006",
    "relatedTransactionId": "txn_900001",
    "eventStatus": "CORRECTION",
    "cardId": "card_88481234",
    "cardNoMask": "486532******1298",
    "cardType": "BUDGET",
    "transactionType": "AUTH_CORRECTION",
    "originalAmount": "1.20",
    "originalCurrency": "USD",
    "actualAmount": "1.20",
    "actualCurrency": "USD",
    "feeAmount": "0.00",
    "merchantName": "Google Ads",
    "merchantCountry": "US",
    "merchantMcc": "7311",
    "transactionTime": "2026-07-02 12:24:59"
  }
}

金额对账示例

上方授权成功、清算完成示例均假设结算本金为 35.60 USD,已收手续费为 0.53 USD,因此 actualAmount=36.13、feeAmount=0.53。它们是同一交易的两个阶段,不是两笔扣款。

结算本金已收手续费推送 actualAmount
9.00 USD0.64 USD9.64
4.01 USD0.37 USD4.38

以上为 Webhook 金额口径;卡交易查询的 usdAmount 沿用页面展示,可能带收支正负号或因订单修正隐藏原消费费用,不应与推送金额逐字段直接等同。订单修正是关联资金记录,应通过 relatedTransactionId 关联核对,不能把原消费费用和关联修正金额机械累加。

交易字段说明

字段说明
transactionIdVCC 本地交易 ID。
relatedTransactionId关联原交易 ID。退款、撤销、修正类事件通常会返回。
eventStatus本次 Webhook 对应的交易阶段,和外层 eventType 后缀保持一致。
transactionType交易业务类型:普通消费为 PURCHASE,退款为 REFUND,撤销为 REVERSE,消费订单修正为 AUTH_CORRECTION。普通消费在授权与清算阶段均为 PURCHASE,阶段通过 eventType / eventStatus 区分。
originalAmount原始授权或交易金额。
actualAmount本次交易阶段的实际金额快照,币种见 actualCurrency。消费为结算本金绝对值加已收手续费(只加一次);退款、撤销为对应退回本金绝对值减该笔已收手续费。feeAmount 已计入该金额,不要再次加减。原币金额与结算本金可能不同,不应直接用 originalAmount 计算。
feeAmount本条通知确认的商户侧已收手续费,币种与 actualCurrency 一致;未实际收取的部分不计入,全部未收时为 0.00。等待上游确认不等于尚未扣款,已确认本地扣除的费用仍可计入;页面隐藏手续费不改变已确认实收事实。

交易事件处理建议

  • eventId 用于 Webhook 接收幂等;同一事件重试时不要重复入账。
  • transactionId 用于业务订单状态推进;同一 transactionId 可能出现多个 eventType。
  • 授权成功为 eventType=CARD_TRANSACTION.AUTH_SUCCESS、eventStatus=AUTH_SUCCESS;清算完成为 eventType=CARD_TRANSACTION.SETTLED、eventStatus=SETTLED。两阶段的普通消费 transactionType 均为 PURCHASE;同一交易的阶段通知不得作为两笔消费重复入账。
  • relatedTransactionId 用于关联退款、撤销和修正的原交易。
  • PROCESSING 不建议直接作为最终入账依据,应等待成功、失败、清算、退款或撤销类事件推进。

3DS 验证码事件

PhotonPay 3DS 验证码成功写入本地记录后,系统向已显式订阅 CARD_3DS 的商户异步推送 CARD_3DS.OTP_RECEIVED。未订阅该大类的商户不会收到验证码事件。

CARD_3DS.OTP_RECEIVED 示例

{
  "eventId": "card_3ds_otp_98231",
  "eventType": "CARD_3DS.OTP_RECEIVED",
  "eventCategory": "CARD_3DS",
  "eventTime": "2026-08-22 14:31:06",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "otpId": 98231,
    "cardId": "VC202608220001",
    "cardNoMask": "498765******4321",
    "otpCode": "387123",
    "merchantName": "GrabRegistrationSG",
    "originalAmount": "19.99",
    "originalCurrency": "USD",
    "transactionTime": "2026-08-22 14:31:05"
  }
}

3DS 字段说明

字段类型说明
otpIdNumberVCC 3DS 验证码记录 ID,可与 eventId 一起用于排查和幂等。
cardIdStringVCC 对外业务卡 ID。
cardNoMaskString中间使用 * 的脱敏卡号,直接返回且不加密;不会返回完整卡号。
otpCodeString3DS 验证码明文。接收方必须限制访问权限并禁止写入普通日志。
merchantNameString上游回调携带的商品或商户名称。
originalAmountString上游 3DS 回调原始金额,不附加币种。
originalCurrencyString上游 3DS 回调原始币种。
transactionTimeString原始 Webhook 首次接收时间,取 webhook_raw_log.received_at;后台重试或重放不会改变。

安全与幂等建议

  • 使用 eventId 做接收幂等;同一事件重试时 eventId 保持不变。
  • data.otpId 是稳定业务来源标识,可用于事件关联与排查。
  • 请求验签通过后再读取 otpCode,并避免在应用日志、告警或错误响应中输出验证码。

预算操作事件

预算组创建、充值成功和转出成功统一归入 BUDGET_OPERATION。系统手续费结算、预算组补差等内部资金请求不会作为普通预算充值或转出 Webhook 推送。

预算组创建示例

{
  "eventId": "wh_202607020301",
  "eventType": "BUDGET_OPERATION.CREATED",
  "eventCategory": "BUDGET_OPERATION",
  "eventTime": "2026-07-02 13:00:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "budgetId": 9001,
    "budgetNo": "BG202607020001",
    "budgetName": "July Ads Budget",
    "cardGroupId": 301,
    "cardGroupName": "US Ads Group",
    "operationType": "CREATE",
    "operationStatus": "SUCCESS",
    "requestNo": "BG202607020001",
    "currency": "USD",
    "status": "ACTIVE",
    "operationTime": "2026-07-02 12:59:59"
  }
}

预算充值成功示例

{
  "eventId": "wh_202607020302",
  "eventType": "BUDGET_OPERATION.RECHARGE_SUCCESS",
  "eventCategory": "BUDGET_OPERATION",
  "eventTime": "2026-07-02 13:10:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "budgetId": 9001,
    "budgetNo": "BG202607020001",
    "budgetName": "July Ads Budget",
    "cardGroupId": 301,
    "cardGroupName": "US Ads Group",
    "operationType": "RECHARGE",
    "operationStatus": "SUCCESS",
    "requestNo": "BR202607020001",
    "amount": "1000.00",
    "currency": "USD",
    "status": "ACTIVE",
    "operationTime": "2026-07-02 13:09:58"
  }
}

预算转出成功示例

{
  "eventId": "wh_202607020303",
  "eventType": "BUDGET_OPERATION.WITHDRAW_SUCCESS",
  "eventCategory": "BUDGET_OPERATION",
  "eventTime": "2026-07-02 13:20:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "budgetId": 9001,
    "budgetNo": "BG202607020001",
    "budgetName": "July Ads Budget",
    "cardGroupId": 301,
    "cardGroupName": "US Ads Group",
    "operationType": "WITHDRAW",
    "operationStatus": "SUCCESS",
    "requestNo": "BW202607020001",
    "amount": "200.00",
    "currency": "USD",
    "status": "ACTIVE",
    "operationTime": "2026-07-02 13:19:59"
  }
}

测试事件

商户在开发者配置中点击测试推送时,VCC 会发送 WEBHOOK_TEST。该事件只用于连通性和验签调试,不代表业务状态变化。

WEBHOOK_TEST 示例

{
  "eventId": "wh_test_202607020001",
  "eventType": "WEBHOOK_TEST",
  "eventCategory": "WEBHOOK_TEST",
  "eventTime": "2026-07-02 13:30:00",
  "apiVersion": "2026-06-01",
  "merchantId": 10001,
  "data": {
    "message": "VCC Webhook 测试推送"
  }
}

更新日志

NEW

查看 Kimoox Open API 的功能、接口和安全策略更新。

错误码

错误码说明处理建议
400请求参数错误。按接口字段说明修正请求参数。
401API Key 缺失、无效或 API 权限未开启。检查 API Key 和 API 权限状态。
403来源 IP 不在已配置白名单,或签名校验失败。如已配置 IP 白名单,请检查来源 IP;同时检查签名串和 API Secret。
500系统异常。保留 requestId 并联系平台排查。
已复制