CodeGrant
约 4136 字大约 14 分钟
2025-03-07
本文介绍部分本地支付方式的 CodeGrant 签约支付集成方案。商户先引导买家在钱包侧完成一次授权,随后保存对应的支付凭证 token,并在约定的业务范围内继续发起后续支付,而无需买家每次都重新完成签约或重复输入支付账户信息。
这一方案适用于会员服务、订阅续费、周期性权益发放、自动扣费等“先授权、后履约”的业务,也适用于希望降低后续支付摩擦、提升复购或续费转化率的本地钱包场景。
适用支付方式
CodeGrant 仅适用于已支持该能力的钱包或本地支付方式。支持范围请参考 CodeGrant 支付方式列表。
支付流程
流程说明:
- 商户调用 签约接口 获取
authUrl和token,并将authUrl返回前端。 - 买家跳转至支付方式页面完成授权。
- 商户通过 签约成功通知 或 签约查询接口 确认授权结果,并保存已生效的
token。 - 商户服务端基于
token发起后续支付。 - 最终支付结果以 交易异步通知 或 交易查询 为准。
接口列表
CodeGrant 集成通常涉及以下接口和通知:
| 阶段 | 类型 | 文档 | 是否必接 | 用途 |
|---|---|---|---|---|
| 签约 | API | 签约接口 | 必接 | 获取签约链接 |
| 通知 | 签约成功通知 | 必接 | 接收签约结果 | |
| API | 签约查询接口 | 推荐 | 查询签约状态 | |
| 取消授权 | API | 取消授权接口 | 必接 | 使 token 失效 |
| 通知 | 取消授权通知 | 推荐 | 同步取消授权结果 | |
| 支付 | API | 下单并支付 | 必接 | 发起支付 |
| 通知 | 交易异步通知 | 必接 | 接收支付结果 | |
| API | 交易查询 | 推荐 | 查询支付结果 | |
| 退款 | API | 申请退款 | 按业务需要 | 发起退款 |
| 通知 | 退款异步通知 | 推荐 | 接收退款结果 | |
| API | 退款查询 | 推荐 | 查询退款结果 |
集成准备
接入 CodeGrant 前,请先完成 准备工作 中的通用准备。
此外,请额外确认以下 CodeGrant 专属事项:
- 已确认目标钱包或本地支付方式支持 CodeGrant,并完成对应能力开通
- 已准备公网可访问的签约
notificationUrl,以及支付使用的notificationUrl、merchantResultUrl和payResultUrl - 已在商户系统内为买家分配稳定的
merchantUserId,并保证签约、支付、取消授权使用同一值 - 已具备保存
token、支付方式类型、签约状态和商户用户映射关系的能力
集成步骤
请按以下步骤完成集成:
步骤 1:获取签约授权链接
商户服务端调用 签约接口 创建签约请求。成功后,PingPongCheckout 会返回 authUrl,用于引导买家跳转到钱包页面完成签约。
签约请求的关键参数:
| 参数 | 必填 | 说明 |
|---|---|---|
bizContent.requestId | M | 签约请求流水号,全局唯一 |
bizContent.merchantUserId | M | 商户侧用户唯一 ID,后续支付与取消授权时必须保持一致 |
bizContent.paymentMethod.type | M | 本次签约的支付方式类型 |
bizContent.merchantResultUrl | M | 用户完成签约后回到商户页面的地址 |
bizContent.notificationUrl | M | 签约结果异步通知地址 |
bizContent.bizType | M | 固定传 CodeGrant |
bizContent.device.orderTerminal | M | 下单终端。01 H5、02 PC、04 iOS App、05 Android App |
注意
merchantResultUrl 只是买家完成签约后回到商户页面的地址,不代表签约成功。签约最终结果必须以服务端异步通知或主动查询结果为准。
请求示例:
{
"accId": "2022102018024210348883",
"clientId": "2022102018024210348",
"signType": "SHA256",
"sign": "{{Sign}}",
"version": "1.0",
"bizContent": {
"requestId": "BIND_202606220001",
"merchantUserId": "MEMBER_10001",
"merchantResultUrl": "https://www.example.com/codegrant/result",
"notificationUrl": "https://www.example.com/codegrant/bind-notify",
"bizType": "CodeGrant",
"paymentMethod": {
"type": "AlipayHK"
},
"device": {
"orderTerminal": "02"
}
}
}响应关键参数:
| 字段 | 说明 |
|---|---|
bizContent.token | 本次签约关联的业务凭证 token |
bizContent.authUrl | 钱包签约页地址,前端应使用该地址引导买家完成签约 |
响应示例:
{
"bizContent": "{\"token\":\"a15b5f3f79c739f39cc551273b542a90\",\"authUrl\":\"https://g.alipayplus.com/page/aplus-linker/acwallet/authorization.html?scopes=AGREEMENT_PAY%2CUSER_LOGIN_ID&bizContent=%7B%22acquirerId%22%3A%22Z02TE5520000000A%22%2C%22authClientDisplayName%22%3A%22ces%22%2C%22authClientId%22%3A%222023121216311410287%22%2C%22authClientName%22%3A%22xiaodian%22%2C%22authRedirectUrl%22%3A%22https%3A%2F%2Fg.alipayplus.com%2Fpage%2Fac-auth-payment%2Fresult%2Fmobile%2Findex.html%3FloadMode%3D2%26callbackType%3DCommon%26terminalType%3DWEB%26referenceAgreementId%3D17821172581855474%26authRequestId%3D2026062219091305000000002861103%26pspId%3D102216000000000000A%26clientId%3DT_4GGO000000000001%22%2C%22authState%22%3A%2217821172581855474%22%2C%22customerBelongsTo%22%3A%22ALIPAY_HK%22%2C%22pspId%22%3A%22102216000000000000A%22%2C%22referenceAgreementId%22%3A%2217821172581855474%22%2C%22referenceMerchantId%22%3A%222023121216311410287%22%2C%22scopes%22%3A%5B%22AGREEMENT_PAY%22%2C%22USER_LOGIN_ID%22%5D%2C%22terminalType%22%3A%22WEB%22%7D&source=AlipayConnect&needCallback=false\"}",
"sign": "08F61A05EA606424B8EA0F97AF2B0773CD3B082733A77A6AEF54BA38309D4572",
"signType": "SHA256"
}注意
同步响应返回 token 和 authUrl 后,并不代表签约已经生效。只有在收到 签约成功通知 或通过 签约查询接口 确认 status=ACTIVE 后,才可以把该 token 用于后续支付。
步骤 2:跳转至支付方式页面进行授权
商户服务端拿到 authUrl 后,将该地址返回前端,由前端在对应终端中打开钱包签约页面。
function redirectToCodeGrantAuth(authUrl) {
if (!authUrl) return;
const authWindow = window.open(authUrl, '_blank');
if (!authWindow) {
window.location.assign(authUrl);
}
}function redirectToCodeGrantAuthOnWap(authUrl) {
if (!authUrl) return;
window.location.href = authUrl;
}NSURL *url = [NSURL URLWithString:authUrl];
if (url) {
[[UIApplication sharedApplication] openURL:url
options:@{}
completionHandler:^(BOOL success) {
if (!success) {
// 引导买家重试或更换支付方式
}
}];
}try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}步骤 3:获取授权结果
买家完成授权后,商户可通过以下任一方式确认授权结果:
- PingPongCheckout 会向签约请求里的
notificationUrl推送签约授权结果。 - 主动调用 签约查询接口 查询签约授权结果。
签约异步通知请求示例:
{
"accId": "2023121216311410287522",
"bizContent": "{\"notifyType\":\"ACCESS_TOKEN_CREATION\",\"payMethod\":\"AlipayHK\",\"merchantUserId\":\"user00001\",\"token\":\"a15b5f3f79c739f39cc551273b542a90\"}",
"clientId": "2023121216311410287",
"sign": "0FFE63EE9CA214DA745131EDAAC15971C7087C9144E87017C4949F015EB55310",
"signType": "SHA256"
}商户收到异步通知后,应优先返回 HTTP 2xx 确认已接收,再执行内部处理逻辑。响应体没有固定字段要求,下面给出一个常见响应示例:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 2
OK商户也可以根据自身系统设计主动调用 签约查询接口 查询签约状态。该查询既可以作为常规确认方式,也可以用于异步通知延迟、回调处理异常、买家回跳后立即核验、日常状态补查等场景,避免仅根据前端回跳页或签约接口同步响应就判断签约成功。
签约查询请求关键参数:
| 参数 | 说明 |
|---|---|
bizContent.token | 待确认的签约 token,建议直接使用签约接口同步响应中的 token |
bizContent.merchantUserId | 商户侧用户唯一标识,应与签约和后续支付保持一致 |
bizContent.requestId | 查询请求流水号 |
签约查询请求示例:
{
"accId": "2022102018024210348883",
"clientId": "2022102018024210348",
"signType": "SHA256",
"sign": "{{Sign}}",
"version": "1.0",
"bizContent": {
"token": "a15b5f3f79c739f39cc551273b542a90",
"merchantUserId": "user00001",
"requestId": "2026062217440001"
}
}签约查询响应示例:
{
"bizContent": "{\"bindInfos\":[{\"bizType\":\"CodeGrant\",\"payMethod\":\"AlipayHK\",\"clientId\":\"2022102018024210348\",\"token\":\"a15b5f3f79c739f39cc551273b542a90\",\"accId\":\"2022102018024210348883\",\"merchantUserId\":\"user00001\",\"status\":\"ACTIVE\"}],\"managementURL\":\"https://sandbox-acquirer-static.pingpongx.com/payment/bindManage/index.html?code=aUW5WtMMzDltikAcGyKxBc746y8R9su6llj98pE6ut4hMDVf5kVZSkfpBqXh6Zi6EPyHdmsfROgdwb1bvp3tO91Me1qm7zfXFqOy7WcxRxOUfuSphTZuJ6MxmzxhzWW1jdgrdfNhDCSWxq_NsbKdVg==\"}",
"code": "001000",
"description": "Successful request",
"sign": "F253140644209B4A5527613FBD31056B8567584E9EF885CE1CB4A25625A14FAA",
"signType": "SHA256"
}签约查询响应关键参数:
| 字段 | 说明 |
|---|---|
bizContent.bindInfos[].token | 返回的签约 token,应与请求中的 token 一致 |
bizContent.bindInfos[].merchantUserId | 该 token 关联的商户用户标识 |
bizContent.bindInfos[].payMethod | 已签约的钱包或本地支付方式类型 |
bizContent.bindInfos[].status | 签约状态,ACTIVE 表示生效,INVALID 表示不可用 |
处理建议:
- 如果
bindInfos中存在匹配 token 且status=ACTIVE,可将该 token 标记为签约成功,并允许后续支付或取消授权。 - 如果
status=INVALID,应将该 token 标记为失效,不再用于后续支付。 - 如果未查到匹配记录或状态未达到可用条件,先不要发起扣款;可短暂重试查询,或继续等待签约通知后再确认。
步骤 4:发起支付
买家授权成功后,商户即可基于授权关系为买家提供后续代扣服务。买家在后续购物过程中,无需再次输入支付信息或重新完成支付授权,商户可通过服务端发起扣款,由系统自动完成订单对应金额的支付。
后续支付的关键参数如下。
| 参数 | 必填 | 说明 |
|---|---|---|
bizContent.captureDelayHours | M | 固定传 0,表示立即 capture |
bizContent.amount | M | 交易金额 |
bizContent.currency | M | ISO 4217 三位币种 |
bizContent.requestId | M | 支付请求流水号,全局唯一 |
bizContent.merchantTransactionId | M | 商户订单号,订单唯一标识 |
bizContent.notificationUrl | M | 支付结果异步通知地址 |
bizContent.payResultUrl | O | 买家回到商户页面的地址 |
bizContent.shopperIP | M | 买家下单 IP |
bizContent.token | M | 已签约成功的业务凭证 token |
bizContent.bizType | M | 固定传 CodeGrant |
bizContent.merchantUserId | M | 与签约时一致的商户用户 ID |
bizContent.paymentMethod.type | M | 已签约的钱包或本地支付方式类型 |
bizContent.customer.email | C | 用户邮箱。实物类商户与部分支付方式会要求传入 |
bizContent.device.orderTerminal | M | 终端类型 |
请求示例:
{
"accId": "2023042011040310224447",
"clientId": "2023042011040310224",
"signType": "SHA256",
"sign": "{{Sign}}",
"version": "1.0",
"bizContent": {
"captureDelayHours": 0,
"amount": 100,
"currency": "HKD",
"requestId": "2026062313592001",
"payResultUrl": "https://www.example.com/codegrant/pay-result",
"notificationUrl": "https://www.example.com/codegrant/pay-notify",
"merchantTransactionId": "2026062313592001",
"shopperIP": "192.168.1.1",
"token": "502e597aa83bf423a3b8ec8484e7301f",
"bizType": "CodeGrant",
"merchantUserId": "user00001",
"paymentMethod": {
"type": "AlipayHK"
},
"customer": {
"email": "buyer@example.com"
},
"device": {
"orderTerminal": "02"
}
}
}响应示例:
{
"accId": "2023042011040310224447",
"bizContent": "{\"transactionTime\":\"1782194370000\",\"requestId\":\"PMT-U6Q622OZ7I1782194369342\",\"merchantTransactionId\":\"2026062313592001\",\"action\":{\"type\":\"QR_CODE\"},\"currency\":\"HKD\",\"exchangedAmount\":\"100\",\"payResultUrl\":\"https://www.example.com/codegrant/pay-result\",\"exchangedCurrency\":\"HKD\",\"amount\":\"100\",\"transactionId\":\"26062300000450891549\",\"captureDelayHours\":0,\"status\":\"SUCCESS\"}",
"clientId": "2023042011040310224",
"code": "000000",
"description": "Transaction succeeded",
"sign": "4D294D16A4C91886992B630A1D48809749221CCFCF76D41E0BBADB0A709963FD",
"signType": "SHA256"
}注意
调用支付接口时,merchantUserId 必须与签约时传入的值保持一致,否则会出现 token 不存在、token 不匹配或无法使用该 token 支付等问题。
同步响应状态:
bizContent.status | 说明 | 处理建议 |
|---|---|---|
SUCCESS | 同步响应已成功 | 可以更新订单状态,但仍建议以异步通知或查询做最终一致性校验 |
FAILED | 支付失败 | 记录失败原因,引导买家改用其他支付方式或稍后重试 |
PROCESSING | 支付处理中 | 等待异步通知;若长时间无结果,主动调用 交易查询 |
获取支付结果
支付完成后,商户可以通过以下任一方式获取支付结果:
- PingPongCheckout 会向支付请求中的
notificationUrl推送交易结果。 - 主动调用 交易查询 查询交易结果。
支付结果通知示例:
{
"clientId": "2023042011040310224",
"code": "000000",
"bizContent": "{\"exchangedCurrency\":\"HKD\",\"amount\":\"100.000000\",\"transactionTime\":\"1782194370000\",\"transactionId\":\"26062300000450891549\",\"token\":\"502e597aa83bf423a3b8ec8484e7301f\",\"notifyType\":\"RECHARGE\",\"transactionEndTime\":\"1782194377229\",\"requestId\":\"PMT-U6Q622OZ7I1782194369342\",\"merchantTransactionId\":\"2026062313592001\",\"paymentMethod\":{\"type\":\"AlipayHK\"},\"currency\":\"HKD\",\"exchangedAmount\":\"100.000000\",\"captureDelayHours\":0,\"status\":\"SUCCESS\"}",
"sign": "8005BA10CFF17D377322423579D0EEBDAA6FA4EE99D4D3FE28CA0BE9D073E68E",
"accId": "2023042011040310224447",
"description": "Transaction succeeded",
"signType": "SHA256"
}如果通过异步通知获取结果,商户收到通知后应优先返回 HTTP 2xx 确认已接收,再执行内部处理逻辑。
通知响应示例:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 2
OK如果商户未收到异步通知,或希望再次确认最终状态,可主动调用 交易查询 查询交易结果。通常可使用 merchantTransactionId 作为查询条件。
交易查询请求示例:
{
"accId": "2023042011040310224447",
"clientId": "2023042011040310224",
"signType": "SHA256",
"sign": "{{Sign}}",
"version": "1.0",
"bizContent": {
"merchantTransactionId": "2026062313592001"
}
}交易查询响应示例:
{
"accId": "2023042011040310224447",
"bizContent": "{\"threeDSecure\":\"\",\"resultCode\":\"000000\",\"transactionTime\":\"1782194370000\",\"requestId\":\"PMT-U6Q622OZ7I1782194369342\",\"merchantTransactionId\":\"2026062313592001\",\"currency\":\"HKD\",\"exchangedAmount\":\"100.000000\",\"resultDescription\":\"Transaction succeeded\",\"exchangedCurrency\":\"HKD\",\"amount\":\"100.000000\",\"transactionEndingTime\":\"1782194377000\",\"transactionId\":\"26062300000450891549\",\"token\":\"502e597aa83bf423a3b8ec8484e7301f\",\"paymentMethod\":{\"type\":\"AlipayHK\"},\"captureDelayHours\":0,\"status\":\"SUCCESS\"}",
"clientId": "2023042011040310224",
"code": "001000",
"description": "Successful request",
"sign": "B2EC288714CFB3F1892ADADFF8C0053C02FE337BDB0F4F9276EC415E0D0DF6EA",
"signType": "SHA256"
}查询响应关键字段:
| 字段 | 说明 |
|---|---|
bizContent.merchantTransactionId | 商户订单号,用于关联商户侧订单 |
bizContent.transactionId | PingPong 交易流水号 |
bizContent.status | 交易状态,可结合服务端通知或查询结果确认最终状态 |
注意
即使商户页面已经回跳到 payResultUrl,也不能直接认定支付成功。必须以服务端的结果为准。
取消授权
授权完成后,商户必须在商户页面为买家提供取消授权入口,确保买家可以主动管理已建立的授权关系,主要原因如下:
- 保障买家对授权关系的自主管理能力,便于买家根据账户安全策略或实际使用需求,随时取消已有授权。
- 部分支付方式存在系统级限制,同一电子钱包账户在同一商户下通常仅允许保留一个或少量有效授权凭证,因此商户需要支持对历史授权关系进行取消。
商户侧取消授权
如果买家在您的应用内取消授权,您需要调用 取消授权接口 使支付方式的 token 失效。除同步响应外,PingPong 还会根据本次请求中传入的 notificationUrl 向商户服务端推送取消授权通知,用于确认最终结果。通知格式可参考下文的取消授权通知示例。
取消授权请求关键字段:
| 参数 | 说明 |
|---|---|
bizContent.merchantUserId | 商户侧用户唯一标识,应与签约和后续支付保持一致 |
bizContent.requestId | 取消授权请求流水号 |
bizContent.token | 待失效的授权凭证 token |
bizContent.notificationUrl | 取消授权结果异步通知地址 |
取消授权请求示例:
{
"accId": "2023042011040310224447",
"clientId": "2023042011040310224",
"signType": "SHA256",
"sign": "{{Sign}}",
"version": "1.0",
"bizContent": {
"merchantUserId": "user00001",
"requestId": "202606230338001",
"token": "a15b5f3f79c739f39cc551273b542a90",
"notificationUrl": "https://www.example.com/codegrant/unbind-notify"
}
}取消授权响应关键字段:
| 字段 | 说明 |
|---|---|
bizContent.token | 已取消授权的 token |
bizContent.merchantUserId | 该 token 关联的商户用户标识 |
bizContent.status | 取消授权结果状态,INVALID 表示该 token 已失效 |
响应示例:
{
"bizContent": "{\"token\":\"a15b5f3f79c739f39cc551273b542a90\",\"merchantUserId\":\"user00001\",\"status\":\"INVALID\"}",
"code": "001000",
"description": "Successful request",
"sign": "03D06D5F9882B8D3410BB1622487ED63F73B0141ED9084823B492CCF903B43F4",
"signType": "SHA256"
}当响应中的 bizContent.status=INVALID 时,表示该授权凭证已失效,不能再用于后续 CodeGrant 支付。
支付方式侧取消授权
如果买家在支付方式侧取消授权,且该支付方式支持取消授权通知能力,您也会接收到 PingPong 发送给您的取消授权通知。PingPong 会通过调用 签约接口 创建签约请求时传入的 notificationUrl 发送该通知;如果支付方式侧不支持该能力,则不会收到这类通知。
取消授权通知示例:
{
"accId": "2023042011040310224447",
"bizContent": "{\"notifyType\":\"ACCESS_TOKEN_CANCEL_OF_MERCHANT\",\"payMethod\":\"AlipayHK\",\"merchantUserId\":\"user00001\",\"token\":\"502e597aa83bf423a3b8ec8484e7301f\"}",
"clientId": "2023042011040310224",
"sign": "E5960BAAE68C98506318F8C67D27BD4A347F3236E42FACC28B6A52B77773F171",
"signType": "SHA256"
}收到取消授权通知后,商户服务端应先返回 HTTP 2xx 确认已接收,再执行内部处理逻辑,并及时将本地 token 状态更新为不可用。
通知响应示例:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 2
OK