聚合支付接口文档

1. 接入准备

上线前,商户管理员在商户系统的“应用管理”中创建应用。每个商户最多创建 20 个应用,建议按环境和业务系统隔离,例如“商城生产环境”“ERP 测试环境”。

完整密钥只在创建或重置成功后展示一次。调用方必须立即保存到服务端密钥管理系统,不得写入浏览器前端、小程序、APP、日志或代码仓库。

应用状态说明:

密钥轮换说明:

1.1 身份与商户号

2. 统一响应

{
  "code": "00000",
  "msg": "成功",
  "data": {}
}
code含义建议
00000请求成功继续判断 data.status,不能把 HTTP 成功当作业务终态
A0001参数错误修正参数后再提交
A0002鉴权失败、签名错误或请求重放检查签名、时间戳、nonce 和密钥
A0003无权限检查调用方授权范围
B0001业务处理失败按原业务单号查询状态,避免直接换单号重试
C0001系统暂不可用稍后按原业务单号重试或查询

3. 请求鉴权

开放 API 不提供登录接口,也不接收商户后台 JWT、Authorization: Bearer 或登录 Cookie。调用方直接使用在“应用管理”中取得的 appIdapiSecret 对每个请求独立签名;验签通过即代表该应用身份合法。

每个请求必须携带:

Header必填说明
X-App-Id调用方标识
X-Timestamp10 位 Unix 秒时间戳
X-Nonce16~128 位随机字符串;同一 appId 下不可重复
X-Signature64 位小写十六进制 HMAC-SHA256
Content-TypePOST 是application/json; charset=UTF-8

除上述请求头外无需传登录令牌。缺少签名、签名错误、时间戳过期、nonce 重复、应用停用或应用不存在时,系统返回 HTTP 401;开放接口未启用或防重放服务不可用时返回 HTTP 503。

待签名串由六行组成,末尾不追加换行:

HTTP_METHOD
REQUEST_PATH
RAW_QUERY_STRING
X_TIMESTAMP
X_NONCE
SHA256_HEX(RAW_BODY_BYTES)

计算方式:

X-Signature = hex_lower(
  HMAC_SHA256(apiSecret, canonicalString)
)

注意:

Python 签名工具类(以下所有接口示例均基于此工具类):

import hashlib
import hmac
import json
import secrets
import time
import urllib.request


class OpenApiClient:
    def __init__(self, base_url: str, app_id: str, api_secret: str):
        self.base_url = base_url
        self.app_id = app_id
        self.api_secret = api_secret

    def post(self, path: str, payload: dict) -> str:
        body = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
        return self._do_request("POST", path, "", body)

    def get(self, path: str, raw_query: str = "") -> str:
        return self._do_request("GET", path, raw_query, b"")

    def _do_request(self, method: str, path: str, raw_query: str, body: bytes) -> str:
        timestamp = str(int(time.time()))
        nonce = secrets.token_hex(16)
        body_hash = hashlib.sha256(body).hexdigest()
        canonical = "\n".join([method, path, raw_query, timestamp, nonce, body_hash])
        signature = hmac.new(
            self.api_secret.encode("utf-8"),
            canonical.encode("utf-8"),
            hashlib.sha256,
        ).hexdigest()

        url = self.base_url + path + (("?" + raw_query) if raw_query else "")
        req = urllib.request.Request(url, data=body if body else None, method=method)
        req.add_header("X-App-Id", self.app_id)
        req.add_header("X-Timestamp", timestamp)
        req.add_header("X-Nonce", nonce)
        req.add_header("X-Signature", signature)
        if method == "POST":
            req.add_header("Content-Type", "application/json; charset=UTF-8")

        with urllib.request.urlopen(req) as resp:
            return resp.read().decode("utf-8")

Java 签名工具类(以下所有接口示例均基于此工具类):

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.time.Instant;

public class OpenApiClient {

    private static final SecureRandom RANDOM = new SecureRandom();
    private final HttpClient http = HttpClient.newHttpClient();
    private final String baseUrl;
    private final String appId;
    private final String apiSecret;

    public OpenApiClient(String baseUrl, String appId, String apiSecret) {
        this.baseUrl = baseUrl;
        this.appId = appId;
        this.apiSecret = apiSecret;
    }

    /** POST 请求 */
    public String post(String path, String jsonBody) throws Exception {
        return doRequest("POST", path, "", jsonBody);
    }

    /** GET 请求(无请求体) */
    public String get(String path, String rawQuery) throws Exception {
        return doRequest("GET", path, rawQuery, "");
    }

    private String doRequest(String method, String path, String rawQuery, String jsonBody) throws Exception {
        String timestamp = String.valueOf(Instant.now().getEpochSecond());
        String nonce = randomNonce();
        byte[] bodyBytes = jsonBody.getBytes(StandardCharsets.UTF_8);
        String bodyHash = sha256Hex(bodyBytes);
        String canonical = String.join("\n", method, path, rawQuery, timestamp, nonce, bodyHash);
        String signature = hmacSha256Hex(apiSecret, canonical);

        URI uri = rawQuery.isEmpty()
                ? URI.create(baseUrl + path)
                : URI.create(baseUrl + path + "?" + rawQuery);

        HttpRequest.Builder builder = HttpRequest.newBuilder(uri)
                .header("X-App-Id", appId)
                .header("X-Timestamp", timestamp)
                .header("X-Nonce", nonce)
                .header("X-Signature", signature);

        if ("POST".equals(method)) {
            builder.header("Content-Type", "application/json; charset=UTF-8")
                    .POST(HttpRequest.BodyPublishers.ofByteArray(bodyBytes));
        } else {
            builder.GET();
        }

        HttpResponse<String> resp = http.send(builder.build(), HttpResponse.BodyHandlers.ofString());
        return resp.body();
    }

    private static String sha256Hex(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hash = md.digest(data);
        return new BigInteger(1, hash).toString(16);
    }

    private static String hmacSha256Hex(String secret, String data) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return new BigInteger(1, hash).toString(16);
    }

    private static String randomNonce() {
        byte[] buf = new byte[16];
        RANDOM.nextBytes(buf);
        return new BigInteger(1, buf).toString(16);
    }
}

4. 幂等与状态处理

5. 支付

5.1 创建支付

POST /payments

请求字段:

字段必填类型说明
merchantNostring(64)业务方在本系统已审核绑定的资金商户号
outTradeNostring(64)调用方唯一订单号;重试必须保持不变
amountdecimal订单金额,单位:元,必须大于 0
paymentMethodstring支付产品:WECHATALIPAYUNIONPAY
paymentModestring支付交互方式,见下表
businessScenestring(32)业务场景,默认 OFFLINE
authorizationDirectorystring(512)支付授权目录,完整 HTTP/HTTPS 地址
goodsNamestring(128)商品名称
userId条件必填string(128)支付用户标识;小程序、公众号、生活号、JS 支付场景必填
userIpstring(64)用户真实公网 IP,不能使用中台服务器 IP
notifyUrlstring(512)调用方接收支付结果通知的 HTTPS 地址
settlementNotifyUrl条件必填string(512)延迟结算结果回调地址;为空时沿用 notifyUrl
redirectUrlstring(512)支付完成后的页面跳转地址,仅作展示,不能作为支付终态
memostring(85)调用方对账备注
paymentOptionsstring(2048)系统已约定的支付扩展信息 JSON
terminalId条件必填string(64)线下面对面交易终端标识
terminalInfo条件必填string(2048)商家终端场景信息 JSON
settlementModestring(32)结算模式:IMMEDIATE(即时)或 DELAYED(延迟,后续可分账),默认 IMMEDIATE
expireTimedatetime订单过期时间,ISO-8601 本地时间,例如 2026-07-30T18:30:00

paymentMode 支持:

场景额外要求
USER_SCAN用户扫描二维码通常返回可展示的支付数据
MINI_PROGRAM小程序支付userId
WECHAT_OFFIACCOUNT公众号支付userId
ALIPAY_LIFE生活号支付userId
JS_PAYJS 支付userId
SDK_PAYAPP SDK 支付
H5_PAY浏览器 H5 支付通常填写 redirectUrl
UNCONSCIOUS_PAY免密支付须提前开通对应能力
DIRECT_PAY直接支付须提前开通对应能力

Java 示例:

OpenApiClient client = new OpenApiClient("https://{api-host}/openapi/v1", appId, apiSecret);

String body = """
    {
      "merchantNo": "10080000001",
      "outTradeNo": "ORDER202607300001",
      "amount": 1.00,
      "paymentMethod": "WECHAT",
      "paymentMode": "USER_SCAN",
      "goodsName": "测试商品",
      "userIp": "203.0.113.10",
      "notifyUrl": "https://merchant.example.com/callbacks/payment",
      "settlementMode": "IMMEDIATE"
    }
    """;

String result = client.post("/payments", body);
System.out.println(result);

Python 示例:

client = OpenApiClient("https://{api-host}/openapi/v1", app_id, api_secret)

result = client.post("/payments", {
    "merchantNo": "10080000001",
    "outTradeNo": "ORDER202607300001",
    "amount": 1.00,
    "paymentMethod": "WECHAT",
    "paymentMode": "USER_SCAN",
    "goodsName": "测试商品",
    "userIp": "203.0.113.10",
    "notifyUrl": "https://merchant.example.com/callbacks/payment",
    "settlementMode": "IMMEDIATE"
})
print(result)

响应 data 字段:

字段类型说明
outTradeNostring调用方订单号
paymentNostring系统支付单号
amountdecimal订单金额,单位:元
currencystring币种,默认 CNY
statusstring支付状态,见下表
settlementStatusstring清算状态;即时结算为 null
settlementAmountdecimal清算金额,单位:元;未清算为 null
unSplitAmountdecimal可分账余额,单位:元;非延迟结算为 null
settlementTimedatetime清算时间
paymentDatastring支付唤起凭证,可能是 URL 或 JSON 字符串
paidAmountdecimal实付金额,单位:元;未支付为 null
refundAmountdecimal累计已退款金额,单位:元
paidTimedatetime支付成功时间
expireTimedatetime订单过期时间
errorCodestring错误码;正常为 null
errorMessagestring错误描述;正常为 null
syncedAtdatetime最近一次与渠道同步状态的时间

paymentData 是支付唤起凭证,可能是 URL 或 JSON 字符串。调用方应按已开通的 paymentMode 处理,不应解析或依赖未在系统接入说明中约定的扩展字段。

支付状态:

状态终态说明
PENDING已创建,尚未受理支付
PAYING支付处理中
SUCCESS支付成功
FAILED支付失败
CLOSED已关闭或已过期
REFUNDED已全部退款

5.2 查询支付

GET /payments/{outTradeNo}?merchantNo={merchantNo}&refresh=true

参数位置必填说明
outTradeNopath调用方订单号
merchantNoquery资金商户号
refreshquerytrue(默认)同步渠道状态后返回;false 只读本地缓存

Java 示例:

String result = client.get(
    "/payments/ORDER202607300001",
    "merchantNo=10080000001&refresh=true");
System.out.println(result);

Python 示例:

result = client.get(
    "/payments/ORDER202607300001",
    "merchantNo=10080000001&refresh=true")
print(result)

响应 data 字段同 5.1。

6. 退款

6.1 申请退款

POST /refunds

请求字段:

字段必填类型说明
merchantNostring(64)必须与原支付订单所属资金商户号一致
refundRequestNostring(64)调用方退款请求号;全局唯一,只能包含字母、数字和下划线,重试必须保持不变
outTradeNostring(64)原支付接口使用的调用方订单号
amountdecimal退款金额,单位:元;累计不得超过原订单实付金额
reasonstring(128)退款原因
notifyUrlstring(512)调用方接收退款状态通知的 HTTPS 地址

Java 示例:

String body = """
    {
      "merchantNo": "10080000001",
      "refundRequestNo": "REFUND_20260730_0001",
      "outTradeNo": "ORDER202607300001",
      "amount": 1.00,
      "reason": "用户取消订单",
      "notifyUrl": "https://merchant.example.com/callbacks/refund"
    }
    """;

String result = client.post("/refunds", body);
System.out.println(result);

Python 示例:

result = client.post("/refunds", {
    "merchantNo": "10080000001",
    "refundRequestNo": "REFUND_20260730_0001",
    "outTradeNo": "ORDER202607300001",
    "amount": 1.00,
    "reason": "用户取消订单",
    "notifyUrl": "https://merchant.example.com/callbacks/refund"
})
print(result)

响应 data 字段:

字段类型说明
refundRequestNostring调用方退款请求号
outTradeNostring原支付订单号
refundAmountdecimal申请退款金额,单位:元
actualRefundAmountdecimal实际退款金额,单位:元;未完成退款为 null
userReceivedAmountdecimal用户实际到账金额,单位:元
returnedFeedecimal退回手续费,单位:元
reasonstring退款原因
statusstring退款状态,见下表
acceptanceStatusstring受理状态:ACCEPTEDREJECTEDUNKNOWN;最终结果以 status 为准
errorCodestring错误码;正常为 null
errorMessagestring错误描述;正常为 null
retryableboolean当前状态是否允许使用原退款请求号重试
nextActionstring建议的后续操作,见下方说明
requestedAtdatetime退款申请时间
succeededAtdatetime退款成功时间;未成功为 null
syncedAtdatetime最近一次与渠道同步状态的时间
createdAtdatetime记录创建时间
updatedAtdatetime记录更新时间

退款状态:

状态终态说明
CREATED已创建
PROCESSING处理中
UNKNOWN受理结果不确定,必须查询
ACTION_REQUIRED需要人工处理
SUCCESS退款成功
FAILED退款失败
CLOSED已关闭

nextAction 可能为:

说明
WAIT_CALLBACK等待回调,也可主动查询
QUERY使用原退款请求号查询
RETRY_SAME_ID仅在 retryable=true 时使用原请求号重试
MANUAL_PROCESS联系系统人工处理
NONE无需后续动作

6.2 查询退款

GET /refunds/{refundRequestNo}?merchantNo={merchantNo}&refresh=true

参数位置必填说明
refundRequestNopath调用方退款请求号
merchantNoquery资金商户号
refreshquerytrue(默认)同步渠道状态并校准结果;false 读取本地缓存

Java 示例:

String result = client.get(
    "/refunds/REFUND_20260730_0001",
    "merchantNo=10080000001&refresh=true");
System.out.println(result);

Python 示例:

result = client.get(
    "/refunds/REFUND_20260730_0001",
    "merchantNo=10080000001&refresh=true")
print(result)

响应 data 字段同 6.1。

7. 订单分账

发起订单分账前必须满足:

字段封装边界:

7.1 发起订单分账

POST /profit-sharing/orders

请求字段:

字段必填类型说明
receiveMerchantNostring(32 bytes)实际分账接收商户号;不是原订单收款商户号,不要求绑定当前开放应用
businessNostring(64)业务幂等号;同一业务重试必须保持不变
outTradeNostring(64)本系统支付接口使用的调用方订单号
notifyUrlstring(512)调用方接收订单分账结果通知的 HTTPS 地址
allocationModestring(16)分账方式:AMOUNT(按金额,默认)或 PERCENTAGE(按比例)
allocationBaseAmount条件必填decimal(14,2)按比例分账时的计算基准金额,单位:元;仅 PERCENTAGE 模式填写,必须大于 0 且不超过订单剩余可分账金额
releaseRemainingAmountboolean是否在本次分账后释放订单剩余可分账金额,默认 false;仅 AMOUNT 模式可设为 true
detailsarray实际接收商户的分账明细,固定 1 条
details[].amount条件必填decimal(14,2)按金额分账时填写的分账金额,单位:元,必须大于 0;AMOUNT 模式必填且不得填写 percentage
details[].percentage条件必填decimal(3,2)按比例分账时填写的比例,范围 (0,100]PERCENTAGE 模式必填且所有明细合计必须等于 100
details[].descriptionstring(128 bytes)分账明细描述,UTF-8 编码不超过 128 字节

Java 示例:

String body = """
    {
      "receiveMerchantNo": "10080000002",
      "businessNo": "ALLOC_ORDER_20260730_0001",
      "outTradeNo": "ORDER202607300001",
      "notifyUrl": "https://merchant.example.com/callbacks/profit-sharing",
      "allocationMode": "AMOUNT",
      "releaseRemainingAmount": false,
      "details": [
        {
          "amount": 0.80,
          "description": "服务费分账"
        }
      ]
    }
    """;

String result = client.post("/profit-sharing/orders", body);
System.out.println(result);

Python 示例:

result = client.post("/profit-sharing/orders", {
    "receiveMerchantNo": "10080000002",
    "businessNo": "ALLOC_ORDER_20260730_0001",
    "outTradeNo": "ORDER202607300001",
    "notifyUrl": "https://merchant.example.com/callbacks/profit-sharing",
    "allocationMode": "AMOUNT",
    "releaseRemainingAmount": False,
    "details": [
        {
            "amount": 0.80,
            "description": "服务费分账"
        }
    ]
})
print(result)

按比例时:

按金额时:

7.2 查询订单分账

GET /profit-sharing/orders/{businessNo}?receiveMerchantNo={receiveMerchantNo}

参数位置必填说明
businessNopath分账业务幂等号
receiveMerchantNoquery原申请中的实际分账接收商户号

查询接口只接收上述两个业务字段。中台先按当前应用和 businessNo 定位原申请,再校验 receiveMerchantNo 与原申请的实际接收商户一致,并自动取得查询所需的原订单信息;不接收原订单收款商户号、支付机构订单号或内部请求标识。若申请结果不确定,必须使用原 businessNo 和原 receiveMerchantNo 查询,不能换号。

Java 示例:

String result = client.get(
    "/profit-sharing/orders/ALLOC_ORDER_20260730_0001",
    "receiveMerchantNo=10080000002");
System.out.println(result);

Python 示例:

result = client.get(
    "/profit-sharing/orders/ALLOC_ORDER_20260730_0001",
    "receiveMerchantNo=10080000002")
print(result)

响应 data 字段见 8.3。

7.3 申请订单分账资金归还

POST /profit-sharing/order-returns

该接口用于将一笔已成功的订单分账金额归还至原支付订单。一次订单分账申请当前只支持一条分账明细,因此归还时系统根据原支付订单自动定位已成功的分账明细;调用方不传接收商户号、系统请求号或支付机构的订单和分账明细标识。

前置条件:原支付订单属于当前开放应用、原订单分账已成功,且本次归还金额不超过该原分账明细的可归还金额。

请求字段:

字段必填类型说明
outTradeNostring(64)原支付订单的调用方订单号
businessNostring(64)本次资金归还的业务幂等号;重试必须保持不变
amountdecimal(14,2)本次归还金额,单位:元,必须大于 0
reasonstring(128)归还原因

Java 示例:

String body = """
    {
      "outTradeNo": "ORDER202607300001",
      "businessNo": "RETURN_ORDER_20260730_0001",
      "amount": 0.80,
      "reason": "售后归还"
    }
    """;

String result = client.post("/profit-sharing/order-returns", body);
System.out.println(result);

Python 示例:

result = client.post("/profit-sharing/order-returns", {
    "outTradeNo": "ORDER202607300001",
    "businessNo": "RETURN_ORDER_20260730_0001",
    "amount": 0.80,
    "reason": "售后归还"
})
print(result)

响应 data 字段:

字段类型说明
businessNostring本次资金归还业务幂等号
outTradeNostring原支付订单的调用方订单号
statusstringCREATEDPROCESSINGUNKNOWNSUCCESSFAILED
amountdecimal本次归还金额,单位:元
reasonstring归还原因
createdAtdatetime归还申请创建时间
completedAtdatetime归还完成时间;未完成时为 null
errorCodestring仅失败时返回系统统一错误码
errorMessagestring仅失败时返回系统统一错误描述
nextActionstringQUERYREVIEW_AND_RETRYNONE

不会返回也不会接收原支付收款商户号、实际接收商户号、系统内部请求号、底层支付订单号、底层分账请求号或分账明细号。

7.4 查询订单分账资金归还结果

GET /profit-sharing/order-returns/{businessNo}?outTradeNo={outTradeNo}

参数位置必填说明
businessNopath资金归还业务幂等号
outTradeNoquery原支付订单的调用方订单号

系统先校验订单归属,再用内部保存的关联信息查询最新状态;查询响应字段与 7.3 相同。状态不确定时必须使用原 businessNo 查询,不能更换新的业务单号。

Java 示例:

String result = client.get(
    "/profit-sharing/order-returns/RETURN_ORDER_20260730_0001",
    "outTradeNo=ORDER202607300001");
System.out.println(result);

Python 示例:

result = client.get(
    "/profit-sharing/order-returns/RETURN_ORDER_20260730_0001",
    "outTradeNo=ORDER202607300001")
print(result)

8. 余额分账

余额分账不依赖原支付订单,只允许向系统已审核生效的 recipientId 分账。

8.1 发起余额分账

POST /profit-sharing/balances

请求字段:

字段必填类型说明
merchantNostring(64)资金商户号
businessNostring(64)业务幂等号;同一业务重试必须保持不变
notifyUrlstring(512)调用方接收余额分账结果通知的 HTTPS 地址
detailsarray分账接收方明细列表,最多 30 条
details[].recipientIdstring(64)系统分配的分账接收方标识
details[].amountdecimal分账金额,单位:元,必须大于 0
details[].descriptionstring(32)分账明细描述
details[].feeModestring(16)手续费收取方式:DEDUCT_FROM_AMOUNT(从分账金额中扣除,默认)或 CHARGE_SEPARATELY(另行收取)
details[].purposestring(40)分账用途

Java 示例:

String body = """
    {
      "merchantNo": "10080000001",
      "businessNo": "ALLOC_BALANCE_20260730_0001",
      "notifyUrl": "https://merchant.example.com/callbacks/profit-sharing",
      "details": [
        {
          "recipientId": "RECIPIENT_0001",
          "amount": 10.00,
          "description": "业务分润",
          "feeMode": "DEDUCT_FROM_AMOUNT",
          "purpose": "服务费"
        }
      ]
    }
    """;

String result = client.post("/profit-sharing/balances", body);
System.out.println(result);

Python 示例:

result = client.post("/profit-sharing/balances", {
    "merchantNo": "10080000001",
    "businessNo": "ALLOC_BALANCE_20260730_0001",
    "notifyUrl": "https://merchant.example.com/callbacks/profit-sharing",
    "details": [
        {
            "recipientId": "RECIPIENT_0001",
            "amount": 10.00,
            "description": "业务分润",
            "feeMode": "DEDUCT_FROM_AMOUNT",
            "purpose": "服务费"
        }
    ]
})
print(result)

8.2 查询余额分账

GET /profit-sharing/balances/{businessNo}?merchantNo={merchantNo}

参数位置必填说明
businessNopath分账业务幂等号
merchantNoquery资金商户号

Java 示例:

String result = client.get(
    "/profit-sharing/balances/ALLOC_BALANCE_20260730_0001",
    "merchantNo=10080000001");
System.out.println(result);

Python 示例:

result = client.get(
    "/profit-sharing/balances/ALLOC_BALANCE_20260730_0001",
    "merchantNo=10080000001")
print(result)

响应 data 字段见 8.3。

8.3 分账响应

订单分账和余额分账使用统一响应。

响应 data 字段:

字段类型说明
businessNostring分账业务幂等号
outTradeNostring关联的支付订单号;余额分账为 null
statusstring分账整体状态,见下表
divideAmountdecimal分账总金额,单位:元
divideRulestring分账规则:AMOUNT(按金额)或 PERCENTAGE(按比例)
createdAtdatetime分账创建时间
completedAtdatetime分账完成时间;未完成为 null
errorCodestring错误码;正常为 null
errorMessagestring错误描述;正常为 null
nextActionstring建议的后续操作
detailsarray分账明细结果列表
details[].recipientIdstring分账接收方标识
details[].amountdecimal分账金额,单位:元
details[].percentagedecimal分账比例;按金额模式为 null
details[].receivedAmountdecimal接收方实际到账金额,单位:元
details[].feedecimal手续费,单位:元
details[].statusstring该明细的分账状态
details[].errorMessagestring该明细的错误描述

分账状态:

状态说明
CREATED已创建
PROCESSING处理中
UNKNOWN结果不确定,应主动查询
SUCCESS分账成功
FAILED分账失败

余额分账在成功后仍可能因后续退回而更新为失败。调用方不得用“成功后永不变化”的状态机处理余额分账,应以最新事件为准。

9. 业务回调

事件类型:

eventTypebusinessNo 对应字段
payment.status.changedoutTradeNo
payment.settlement.changedoutTradeNo
refund.status.changedrefundRequestNo
profit-sharing.order.status.changed分账 businessNo
profit-sharing.balance.status.changed分账 businessNo

回调请求头:

Header说明
X-Callback-App-Id调用方标识
X-Callback-TimestampUnix 秒时间戳
X-Callback-Event-Id全局唯一事件 ID
X-Callback-Event-Type事件类型

回调体字段:

字段类型说明
eventIdstring全局唯一事件 ID,用于幂等去重
eventTypestring事件类型
occurredAtdatetime事件发生时间(UTC)
appIdstring调用方应用标识
merchantNostring资金商户号;订单分账事件中为原支付订单收款商户号,不是 receiveMerchantNo
businessNostring关联的业务单号
statusstring最新状态
dataobject事件附加数据

回调体示例:

{
  "eventId": "7edb6c9a-1f7d-4aa7-a147-16c8c9ef73d4",
  "eventType": "refund.status.changed",
  "occurredAt": "2026-07-30T09:40:00Z",
  "appId": "app_0123456789abcdef01234567",
  "merchantNo": "10080000001",
  "businessNo": "REFUND_20260730_0001",
  "status": "SUCCESS",
  "data": {}
}

接收要求:

  1. 校验 appIdmerchantNo 与本应用一致。
  2. 使用 eventId 做幂等去重。
  3. 根据 eventType + businessNo 更新业务状态,并允许合法的后续状态修正。
  4. 处理成功后返回 HTTP 2xx,响应体必须是纯文本 SUCCESS
  5. 非 2xx 或响应体不是 SUCCESS 会触发重试;调用方不得依赖固定重试次数或间隔。