Appearance
支付绑卡
本组接口仅服务
CXH_DEDUCT的"A.1 自绑"子流程(用户在 CXH 端绑卡,CXH 持有协议)。
- 走
CHANNEL_COLLECT的渠道:无需本组接口,直接查阅 订阅下单- 走
CXH_DEDUCT的 A.2 协议共享(用户已在渠道侧绑卡,渠道将支付机构协议号共享给 CXH):无需本组接口,在 订阅下单 入参中传sharedAgreement子对象协议(
agreement)代表用户与某个支付通道签订的代扣授权。绑卡与订阅下单分离:绑卡仅完成"卡 + 实名 + 代扣授权"的建立,无需指定 SPU;后续 订阅下单 时通过bindOrderNo关联,同一份绑卡可被同一渠道下的多个 SPU 订阅复用。
多卡多通道场景
- 同一用户可在多个支付通道各绑一张卡,每张卡独立
agreement - 同一用户在同一支付通道也可绑多张不同银行卡,每张卡独立
agreement - 绑卡时通过入参
paymentChannelCode指定使用哪个通道 - 可选的
paymentChannelCode列表由 BD 为每个渠道单独授权,渠道通过payment-channels/list获取动态列表(亦可向 BD 索取) - 绑卡接口的
bankCode使用支付通道支持的银行编码;若通道返回supportedBanks=["*"]表示不限,否则必须从supportedBanks列表中取值
POST /openapi/v1/payment-channels/list
查询当前渠道已授权的支付通道列表。建议渠道前端进入绑卡页时先调用一次,动态展示给用户选择。
请求
无 body(空对象 {})。
响应 data
| 字段 | 说明 |
|---|---|
items | 已授权通道列表 |
items[].code | 通道编码,作为 bind-sms 入参 paymentChannelCode 或 sharedAgreement.paymentChannelCode |
items[].displayName | 终端用户可见的名称 |
items[].isDefault | 该渠道的默认通道,列表内至多一项为 true;bind-sms 未传 paymentChannelCode 时由此兜底 |
items[].shareEnabled | 是否开通 A.2 协议共享。true 表示渠道可在 订阅下单 用 sharedAgreement 入参跳过 CXH 绑卡,直接传入支付机构的协议号。需双方在该支付机构提前完成协议共享对接 |
items[].supportedBanks | 该通道支持的银行编码列表;["*"] 表示不限 |
json
{
"items": [
{
"code": "CHANNEL_A",
"displayName": "示例通道 A",
"isDefault": true,
"shareEnabled": true,
"supportedBanks": ["ICBC", "ABC", "CCB", "BOC"]
},
{
"code": "CHANNEL_B",
"displayName": "示例通道 B",
"isDefault": false,
"shareEnabled": false,
"supportedBanks": ["*"]
}
]
}POST /openapi/v1/agreements/bind-sms
发送绑卡验证码。5 个敏感字段必须 AES 加密,详见 签名 + 字段加密。
请求
| 字段 | 必填 | 说明 |
|---|---|---|
channelUserId | ✓ | 渠道侧用户唯一 ID |
paymentChannelCode | △ | 支付通道编码;若该渠道仅授权一个通道或配置了默认通道,可不传(CXH 用默认值兜底)。传值必须在 BD 提供的授权列表内,否则 403003 PAYMENT_CHANNEL_NOT_ALLOWED |
bankCode | △ | 银行编码;通道要求银行编码时必填,取值参考 payment-channels/list 返回的 items[].supportedBanks。例如 CCB(建设银行)、ABC(农业银行)。该字段不是敏感字段,明文传输 |
mobileEncrypted | ✓ | 用户登录手机号(AES 加密;不是银行预留手机号)。首次发码成功后,该手机号与 (channelId, channelUserId) 强绑定;后续同 (channelId, channelUserId) 再次调用 bind-sms / orders/create 入参 mobile 必须一致,否则 410010 CHANNEL_USER_MOBILE_MISMATCH。如需修改请联系 BD 人工处理 |
bankCardNoEncrypted | ✓ | 银行卡号(AES 加密) |
certificateNoEncrypted | ✓ | 身份证号(AES 加密) |
realNameEncrypted | ✓ | 真实姓名(AES 加密) |
bankMobileEncrypted | ✓ | 银行预留手机号(AES 加密) |
certType | — | 证件类型,默认 ID_CARD |
productCode | — | SPU 编码;若绑卡时已知目标 SPU 可传入,CXH 会校验该渠道是否被授权销售;留空表示通用绑卡,与具体 SPU 解耦 |
bindOrderNo | — | 二次发码时传入(同一绑卡单重新触发短信);二次发码不可修改 paymentChannelCode |
json
{
"channelUserId": "u_001",
"paymentChannelCode": "CHANNEL_A",
"bankCode": "CCB",
"mobileEncrypted": "cxh_aes_v1:...",
"bankCardNoEncrypted": "cxh_aes_v1:...",
"certificateNoEncrypted": "cxh_aes_v1:...",
"realNameEncrypted": "cxh_aes_v1:...",
"bankMobileEncrypted": "cxh_aes_v1:...",
"certType": "ID_CARD"
}响应 data
| 字段 | 说明 |
|---|---|
bindOrderNo | 绑卡单号;后续 bind-confirm 与 orders/create 用此关联 |
paymentChannelCode | 实际生效的通道编码(入参未传时返回兜底默认值) |
agreementStatus | BIND_ING(短信已发送,等待用户输入验证码) |
smsStatus | SEND_SUCCESS / SEND_FAIL |
failReason | 仅 smsStatus=SEND_FAIL 时返回,失败原因描述 |
json
{
"bindOrderNo": "BIND...",
"paymentChannelCode": "CHANNEL_A",
"agreementStatus": "BIND_ING",
"smsStatus": "SEND_SUCCESS"
}POST /openapi/v1/agreements/bind-confirm
提交短信验证码,完成绑卡。smsCodeEncrypted 必须 AES 加密。
请求
| 字段 | 必填 | 说明 |
|---|---|---|
bindOrderNo | ✓ | bind-sms 返回的绑卡单号 |
smsCodeEncrypted | ✓ | 用户输入的短信验证码(AES 加密) |
json
{
"bindOrderNo": "BIND...",
"smsCodeEncrypted": "cxh_aes_v1:..."
}响应 data
| 字段 | 说明 |
|---|---|
agreementNo | 协议号(绑卡成功后由 CXH 生成) |
agreementStatus | BIND_SUCCESS / BIND_FAIL |
bankCardTailNo | 银行卡号后 4 位,用于回显 |
failReason | 仅 agreementStatus=BIND_FAIL 时返回,失败原因描述 |
json
{
"agreementNo": "AGT...",
"agreementStatus": "BIND_SUCCESS",
"bankCardTailNo": "0123"
}成功后 agreementNo 即可在 订阅下单 通过 bindOrderNo 关联使用。订阅下单时无需再传 paymentChannelCode,CXH 从 agreement 自动获取。
POST /openapi/v1/agreements/user-data
按查询条件返回该用户在 CXH 已绑卡的 agreement 列表(密文回传,渠道侧自行解密)。至少传一个查询条件;敏感字段必须 AES 加密。
请求
| 字段 | 必填 | 说明 |
|---|---|---|
channelUserId | △ | 渠道侧用户唯一 ID;与 bankCardNoEncrypted / certificateNoEncrypted 至少传一个 |
bankCardNoEncrypted | △ | 银行卡号(AES 加密);用于按卡号反查 |
certificateNoEncrypted | △ | 身份证号(AES 加密);用于按证件号反查 |
json
{
"channelUserId": "u_001"
}未传任何查询条件时返回 400001。
响应 data
| 字段 | 说明 |
|---|---|
bankDataList | 已绑 agreement 列表,空列表表示该用户在当前渠道无已绑卡 |
bankDataList[].bindOrderNo | 绑卡单号 |
bankDataList[].agreementNo | 协议号 |
bankDataList[].bankCardNoEncrypted | 银行卡号密文(渠道侧用 aesKey 解密) |
bankDataList[].certificateNoEncrypted | 身份证号密文 |
bankDataList[].realNameEncrypted | 真实姓名密文 |
bankDataList[].bankMobileEncrypted | 银行预留手机号密文 |
bankDataList[].agreementStatus | BIND_SUCCESS / CANCELED / REPLACED 等 |
json
{
"bankDataList": [
{
"bindOrderNo": "BIND...",
"agreementNo": "AGT...",
"bankCardNoEncrypted": "cxh_aes_v1:...",
"certificateNoEncrypted": "cxh_aes_v1:...",
"realNameEncrypted": "cxh_aes_v1:...",
"bankMobileEncrypted": "cxh_aes_v1:...",
"agreementStatus": "BIND_SUCCESS"
}
]
}字段名以
Encrypted结尾的均为 AES 密文,渠道侧使用aesKey按 签名 + 字段加密 § 字段级 AES 描述的格式解密。