MERCHANT API DOCUMENTATION
生产环境商户 API 对接文档
接口版本 v1 · HTTPS · UTF-8 · application/json
1. 快速接入
商户 API 域名和管理后台域名不同。所有程序接口必须使用
https://weiyi9991weiyipay.xyz,不要使用管理后台域名。| 对接文档 | https://weiyi9991weiyipay.xyz/merchant-api-docs.html |
|---|---|
| 创建订单 | POST https://weiyi9991weiyipay.xyz/openapi/v1/orders |
| 查询订单 | GET https://weiyi9991weiyipay.xyz/openapi/v1/orders/{system_no} |
| 查询费率 | GET https://weiyi9991weiyipay.xyz/openapi/v1/rates |
| 平台回调出口 IP | 148.66.16.74(请加入商户回调服务器白名单) |
- 向平台运营获取商户号、商户密钥和已开通的产品编码。
- 校准商户服务器时间,生成 Unix 秒级时间戳和每次唯一的 Nonce。
- 按本文规则签名,先调用费率接口验证认证是否正确。
- 创建订单,保存平台返回的
system_no,将客户跳转至payment_url。 - 实现并公网开放
notify_url,验签、幂等处理通知并返回约定成功应答。
2. 请求认证与签名
创建订单、查询订单和查询费率都必须携带签名请求头。登录账号和登录密码不参与 API 认证。
| 请求头 | 必填 | 说明 |
|---|---|---|
X-Merchant-No | 是 | 平台分配的商户号,不是登录账号 |
X-Timestamp | 是 | Unix 秒级时间戳,与平台时间误差不得超过 300 秒 |
X-Nonce | 是 | 至少 12 个字符;每次请求重新生成,10 分钟内不可重复 |
X-Signature | 是 | HMAC-SHA256 结果的小写十六进制字符串 |
Content-Type | POST 必填 | application/json; charset=UTF-8 |
X-Client-User-Agent | 建议 | 付款客户真实浏览器 User-Agent;不参与签名 |
签名原文
METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + NONCE + "\n" + RAW_BODY创建订单签名原文示例
POST
/openapi/v1/orders
1792236170
43531248c0494b9aa2950230849f326b
{"merchant_order_no":"T10001","product_code":"203","amount":"100.00","client_device":"pc","notify_url":"https://merchant.example/callback"}signature = hex_lowercase(HMAC_SHA256(商户密钥, UTF8(签名原文)))重要:先生成最终 JSON 字符串,用同一份原始字节同时签名和发送。签名后如果框架重新排序字段、增加空格或改变换行,签名就会失败。GET 请求的
RAW_BODY 为空字符串,但 Nonce 后面的换行仍必须存在。3. 可直接参考的签名代码
Java 11+
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HexFormat;
import java.util.UUID;
String merchantNo = "平台分配的商户号";
String secret = "平台分配的商户密钥";
String path = "/openapi/v1/orders";
String body = "{\"merchant_order_no\":\"T10001\",\"product_code\":\"203\",\"amount\":\"100.00\",\"client_device\":\"pc\",\"notify_url\":\"https://merchant.example/callback\"}";
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String nonce = UUID.randomUUID().toString().replace("-", "");
String text = "POST\n" + path + "\n" + timestamp + "\n" + nonce + "\n" + body;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
String signature = HexFormat.of().formatHex(mac.doFinal(text.getBytes(StandardCharsets.UTF_8)));
HttpRequest req = HttpRequest.newBuilder(URI.create("https://weiyi9991weiyipay.xyz" + path))
.header("Content-Type","application/json; charset=UTF-8")
.header("X-Merchant-No",merchantNo).header("X-Timestamp",timestamp)
.header("X-Nonce",nonce).header("X-Signature",signature)
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)).build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
Node.js
const crypto = require('crypto');
const path = '/openapi/v1/orders';
const body = JSON.stringify(order);
const timestamp = Math.floor(Date.now()/1000).toString();
const nonce = crypto.randomUUID().replaceAll('-','');
const text = `POST\n${path}\n${timestamp}\n${nonce}\n${body}`;
const signature = crypto.createHmac('sha256', secret)
.update(text,'utf8').digest('hex');PHP
$path = '/openapi/v1/orders';
$body = json_encode($order, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(16));
$text = "POST\n{$path}\n{$timestamp}\n{$nonce}\n{$body}";
$signature = hash_hmac('sha256', $text, $secret);4. 创建订单
POST
/openapi/v1/orders| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
merchant_order_no | string | 是 | 商户订单号,同一商户内唯一,最长 64 位 |
product_code | string | 是 | 平台为该商户开通并启用的产品编码 |
amount | string/number | 是 | 大于 0,建议两位小数字符串,如 100.00 |
client_device | string | 建议 | ios、android 或 pc |
notify_url | string | 强烈建议 | 本笔订单的公网异步通知地址,优先于后台默认回调地址 |
请求正文
{
"merchant_order_no": "T202610170001",
"product_code": "203",
"amount": "100.00",
"client_device": "android",
"notify_url": "https://merchant.example.com/payment/callback"
}成功响应(HTTP 200)
{
"code": 0,
"message": "success",
"data": {
"system_no": "WEIYI202610170001...",
"merchant_order_no": "T202610170001",
"status": "pending",
"payment_url": "https://..."
}
}商户必须保存 system_no,并将付款客户跳转到 payment_url。HTTP 超时或连接中断时,先查单确认,不要直接换订单号重复下单。
5. 查询订单与费率
GET
/openapi/v1/orders/{system_no}签名 PATH 必须替换成真实系统单号路径;GET 请求体为空。
{"code":0,"message":"success","data":{"system_no":"WEIYI...","merchant_order_no":"T...","amount":"100.00","status":"paid","created_at":"2026-10-17T09:30:00+00:00"}}
| 状态 | 说明 | 商户处理 |
|---|---|---|
pending | 等待支付 | 继续等待回调或定时查单 |
paid | 支付成功 | 成功入账,必须幂等 |
failed | 订单失败 | 停止支付流程 |
closed | 订单关闭 | 停止支付流程 |
reversed | 已冲正 | 撤销此前成功结果,必须幂等 |
GET
/openapi/v1/rates使用相同签名请求头,只返回该商户已开通且启用的产品。
{"code":0,"message":"success","data":[{"code":"203","name":"产品名称","fee_rate":"13.000"}]}fee_rate 单位是百分比,13.000 表示 13%。
6. 支付结果与冲正异步回调
平台向订单 notify_url 发送 POST application/json。同一事件可能重试,商户必须以 event_id 幂等;同一订单可能先收到 paid,之后收到独立的 reversed。
| 请求头 | 说明 |
|---|---|
X-Merchant-No | 商户号 |
X-Callback-Event | 事件 ID,与正文 event_id 相同 |
X-Signature | HMAC-SHA256(原始回调 JSON 字节, 商户密钥) 的小写十六进制结果 |
支付成功事件
{"event_id":"uuid","system_no":"WEIYI...","merchant_order_no":"T...","amount":"100.00","status":"paid","confirmation_source":"upstream_callback","paid_at":"2026-10-17T11:26:45+00:00"}冲正事件
{"event_id":"另一个uuid","system_no":"WEIYI...","merchant_order_no":"T...","amount":"100.00","status":"reversed","confirmation_source":"reversal","paid_at":"2026-10-17T11:26:45+00:00"}
- 读取原始请求体字节,不要解析后重新序列化再验签。
- 用商户密钥计算 HMAC-SHA256,与
X-Signature安全比较。 - 核对商户号、事件 ID、订单号、金额和状态。
- 以
event_id建唯一约束;重复事件直接返回成功,不重复入账或扣账。 paid执行成功入账;reversed撤销此前成功入账。- 本地事务提交成功后再返回成功应答。
平台认可的成功应答
HTTP 200
successHTTP 200
ok也支持:
{"success":true}
{"code":0}
{"code":200}只返回 HTTP 200 但正文为空,或返回未约定的 JSON,平台仍会判定回调失败并重试。不能把
reversed 当成未知状态拒绝,它是合法冲正事件。7. HTTP 状态码与常见问题
| HTTP | 原因 | 处理 |
|---|---|---|
| 400 | JSON 缺字段、金额或参数格式错误 | 检查请求体和字段类型 |
| 401 | 商户号、时间戳或签名无效 | 校时;确认 PATH 和原始 JSON 完全一致 |
| 403 | 来源 IP 不在白名单 | 向平台登记商户服务器固定出口 IP |
| 404 | 域名/路径错误,或订单、产品不存在 | 确认使用商户 API 域名及正确编码 |
| 409 | Nonce/订单号重复、无可用通道或终端不匹配 | 重新生成 Nonce;重复订单先查单;联系运营检查绑定 |
| 422 | 必要请求头或参数结构缺失 | 检查四个签名头及 JSON |
| 429 | 请求超过频率限制 | 降低并发并做指数退避 |
| 502 | 全部上游通道拉单失败 | 保留响应并提供商户订单号给平台 |
| 503 | 平台临时暂停进单或服务不可用 | 指数退避重试,并先查原订单 |
上线前自检
- 程序接口域名是
weiyi9991weiyipay.xyz。 - 服务器已通过 NTP 校时。
- Nonce 至少 12 位且每次不同。
- 签名使用小写十六进制 HMAC-SHA256。
- 签名 JSON 与实际发送 JSON 完全相同。
- 回调地址公网可访问,并允许来源 IP
148.66.16.74。 - 回调支持
paid和reversed,以event_id幂等。 - 成功后明确返回
success、ok或标准成功 JSON。 - 日志不得记录完整商户密钥。