请求签名
| 请求头 | 说明 |
|---|---|
X-App-Id | API应用的 App ID |
X-Timestamp | 当前 Unix 时间戳,允许偏差 300 秒 |
X-Nonce | 8 至 64 位随机字符串,同一应用不可重复 |
X-Signature | HMAC-SHA256 小写十六进制签名 |
Content-Type | application/json |
待签名字符串
METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + NONCE + "\n" + SHA256(RAW_BODY)
PATH 以斜线开头,不包含域名和查询参数;GET 请求的 RAW_BODY 为空字符串。发送的 JSON 原文必须与计算摘要时完全一致。
PHP 7.4
$method = 'POST';
$path = '/api/v1/payments';
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(16));
$body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$canonical = strtoupper($method) . "\n" . $path . "\n" . $timestamp . "\n" . $nonce . "\n" . hash('sha256', $body);
$signature = hash_hmac('sha256', $canonical, $apiSecret);
POST
/api/v1/payments创建会员收款订单。相同 App ID 与商户订单号重复请求时返回原订单。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_trade_no | string | 是 | 1 至 32 位字母、数字、下划线或短横线 |
channel | string | 是 | wechat / alipay |
scene | string | 是 | web / scan / app / h5 |
mode | string | 是 | goods / amount |
amount | decimal | 是 | 支付金额,大于 0 且不超过 99999999.99 |
title | string | 否 | 支付标题,最长 120 个字符 |
items | array | goods 模式必填 | goods_id + quantity |
receiver | object | 可选 | goods 模式可不传,系统会在支付成功时自动生成留证地址;传入时兼容现有履约流程 |
goods 模式请求
{
"out_trade_no": "M202607220001",
"channel": "wechat",
"scene": "scan",
"mode": "goods",
"amount": "199.00",
"title": "商城收款订单",
"items": [{"goods_id": 1, "quantity": 1}],
"receiver": {
"name": "张三",
"mobile": "13800000000",
"province": "浙江省",
"city": "杭州市",
"area": "西湖区",
"address": "文一西路100号",
"postcode": "310000"
}
}
amount 模式请求
{
"out_trade_no": "M202607220002",
"channel": "alipay",
"scene": "web",
"mode": "amount",
"amount": "99.00",
"title": "服务收款订单"
}
支付结果根据场景返回 payment.redirect_url、payment.qr_code 或 payment.sdk_payload;goods 模式如未提供收货信息,系统会自动补生成留证地址。
GET
/api/v1/payments/{order_no}order_no 可使用平台订单号或当前应用的商户订单号。
{
"code": 0,
"message": "查询支付成功",
"data": {
"order_no": "MP202607220001",
"out_trade_no": "M202607220001",
"channel": "wechat",
"scene": "scan",
"mode": "goods",
"amount": "199.00",
"cost_amount": "38.00",
"status": "paid",
"fulfillment_status": "pending_ship",
"freeze_status": "deducted",
"evidence_address": "浙江省杭州市西湖区文一西路100号2幢688室",
"shipping": {"status": "pending", "company": "", "no": "", "time": 0},
"payment": {"qr_code": "weixin://..."}
},
"request_id": "20260722120000abcdef123456"
}
POST
/api/v1/payments/{order_no}/fulfillment仅用于已支付且履约状态为 pending_goods 的纯金额订单,每个支付订单最多补充一次。
{
"items": [{"goods_id": 1, "quantity": 2}],
"receiver": {
"name": "张三",
"mobile": "13800000000",
"province": "浙江省",
"city": "杭州市",
"area": "西湖区",
"address": "文一西路100号",
"postcode": "310000"
}
}
GET
/api/v1/fulfillments/{order_no}{
"code": 0,
"message": "查询履约成功",
"data": {
"order_no": "MP202607220001",
"out_trade_no": "M202607220001",
"status": "shipped",
"shipping_status": "shipped",
"evidence_address": "浙江省杭州市西湖区文一西路100号2幢688室",
"shipping_company": "顺丰速运",
"shipping_no": "SF202607220001",
"shipping_time": 1784700000
},
"request_id": "20260722120000abcdef123456"
}
处理状态
pending / paid / failed / expired发货状态
none / pending_goods / pending_ship / shipped冻结状态
none / frozen / deducted / releasedWebhook
通知使用 API 应用的同一密钥和相同签名算法;METHOD 固定为 POST,PATH 取登记 Webhook URL 的路径。返回任意 2xx 状态码即视为成功,不跟随跳转。
{
"event_id": "7f6d...",
"event_type": "payment.succeeded",
"created_at": 1784700000,
"data": {
"order_no": "MP202607220001",
"out_trade_no": "M202607220001",
"transaction_id": "420000000000",
"status": "paid"
}
}
| 事件 | 触发时机 |
|---|---|
payment.succeeded | 支付成功 |
payment.failed | 支付失败 |
payment.expired | 支付订单过期 |
fulfillment.created | 补充履约已创建 |
fulfillment.shipped | 订单已发货 |
失败重试间隔:1 分钟、5 分钟、15 分钟、1 小时、6 小时、24 小时。接收方应按 event_id 幂等处理。
响应与错误码
{"code": 40106, "message": "请求签名验证失败", "data": null, "request_id": "..."}
| code | 说明 |
|---|---|
0 | 成功 |
40001 / 40002 | JSON 请求体或订单号不正确 |
40101 | 鉴权请求头缺失 |
40102 / 40103 | Nonce 格式或时间戳不正确 |
40104 / 40105 | API 应用不存在或已停用 |
40106 | 签名验证失败 |
40107 | Nonce 重复,请求被判定为重放 |
40109 | 请求 IP 不在白名单 |
42200 / 42201 | 业务参数或当前订单状态不允许 |
50000 | 服务端处理失败 |