MerchantCenter 商户开放 API 对接指南

文中的 <...> 均为需要替换的占位值。

接入前请确认以下信息:

接入凭据准备

  1. API Key 未生成前,开放接口无法通过鉴权。
  2. API Key 可在商户后台完成验证后生成和查看。
  3. 后台平时显示 API Key 脱敏值,完成验证后可临时查看完整值。
  4. API Key 重置成功后,旧 Key 立即失效。
  5. 商户后台的验证信息不随接口请求发送,也不参与订单签名。

1. 接口清单

业务方法Path
查询平台商户余额GET/open/mc/merchantBalance/query
创建代收订单POST/open/mc/merchantPayin/create
查询代收订单GET/open/mc/merchantPayin/query
提交代收 UTRPOST/open/mc/merchantPayin/submitUtr
代收补单POST/open/mc/merchantPayin/makeup
查询 UPI 是否已存在GET/open/mc/merchantPayin/upiQuery
查询 UTR 是否已存在GET/open/mc/merchantPayin/utrQuery
创建代付订单POST/open/mc/merchantPayout/create
查询代付订单GET/open/mc/merchantPayout/query

2. 通用请求与响应

2.1 请求 Header

所有商户请求和平台异步通知均使用以下五个认证 Header:

Header必填说明
x-merchant-no平台分配的商户号
x-timestampUnix 秒级时间戳;默认允许与平台服务器时间误差不超过 300 秒
x-nonce本次请求唯一随机串,16~64 位,只允许字母、数字、_-
x-sign-version固定为 v2;缺失或其他版本均拒绝
x-signHMAC-SHA256 签名,64 位小写十六进制字符串

POST 请求还应携带:

Content-Type: application/json

请求签名要求:

2.2 来源 IP 策略

接口范围IP 白名单要求
全部开放接口强制要求。商户必须提前登记固定公网出口 IP;来源 IP 不匹配时请求将被拒绝

来源 IP 要求:

2.3 字段规则

规则说明
金额使用字符串,必须大于 0,固定两位小数,例如 "500.00"
可选字段无值时建议省略;请求体或通知体可以携带 null
GET 参数使用 URL query;同一个 key 只传一次
订单定位orderNomerchantOrderNo 二选一,只能传一个
未知字段未在对应接口字段表中声明的字段会被拒绝

2.4 通用响应

成功:

{
  "code": 1000,
  "message": "success",
  "data": {}
}

失败:

{
  "code": 40100,
  "message": "Request parameter is invalid",
  "data": null
}

创建订单在业务受理前失败时,data 仍会保留商户订单号和失败状态:

{
  "code": 40302,
  "message": "Service is temporarily unavailable",
  "data": {
    "merchantOrderNo": "ORDER-EXAMPLE-001",
    "status": "FAILED"
  }
}

只有创建成功并返回过 orderNo 的订单,后续查询和异步通知才会携带平台订单号。

3. 签名与验签

3.1 签名参数

请求方向/方法参与 payload SHA-256 的内容
商户 POST 请求平台JSON Body 参数按 3.2 节删除空值、排序后的稳定 JSON
商户 GET 请求平台URL query 参数按 3.2 节删除空值、排序后的稳定 JSON
平台 POST 通知商户通知 JSON 参数按 3.2 节删除空值、排序后的稳定 JSON

path 规则:

3.2 参数清理与排序

GET、POST 和平台通知使用同一规则:删除空值参数,按字段名字典序递归排序,再序列化为稳定 JSON。该处理只用于签名,不改变实际发送的 JSON。

类型规则
对象删除空值字段后,所有层级的 key 按字典序升序排列
数组保持原顺序;元素递归清理,空值元素不参与签名
有效标量字符串、数字、布尔值使用标准 JSON;0false"0" 必须参与
空值nullundefined、空字符串、纯空白字符串、非有限数字不参与签名
重复 query key只取第一个值;调用方应避免重复 key
输出UTF-8,不含缩进、额外空格或换行

示例 GET query 对象:

{
  "merchantOrderNo": "MP001",
  "amount": "500.00",
  "currency": "INR",
  "utr": null
}

参与摘要计算的稳定 JSON:

{"amount":"500.00","currency":"INR","merchantOrderNo":"MP001"}

只要有效业务参数相同,JSON 字段原始顺序、空格和换行不会改变签名;字段名称或有效值发生变化时必须重新计算签名。

3.3 八行签名原文

先计算:

payloadSha256 = hex_lower(SHA256(payloadBytes))

再使用单个换行符 \n 拼接以下八行,末尾不增加换行:

MCV2-HMAC-SHA256
v2
<UPPERCASE_HTTP_METHOD>
<URL_PATHNAME>
<MERCHANT_NO>
<TIMESTAMP_UNIX_SECONDS>
<NONCE>
<PAYLOAD_SHA256>

用商户后台生成并安全保存的 API Key 对 canonical text 的 UTF-8 字节计算 HMAC-SHA256,并输出小写十六进制字符串:

sign = hex_lower(HMAC_SHA256(apiKey, canonicalText))

签名适用范围:

4. 查询平台商户余额

GET /open/mc/merchantBalance/query
GET /open/mc/merchantBalance/query?currency=INR

Query:

字段必填说明
currency币种,例如 INR;不传返回该商户已有的全部币种账户

成功响应 data

{
  "merchantNo": "<MERCHANT_NO>",
  "balances": [
    {
      "currency": "INR",
      "balance": "1000.00",
      "availableBalance": "900.00",
      "frozenBalance": "100.00"
    }
  ]
}

余额返回说明:

5. 创建代收订单

POST /open/mc/merchantPayin/create
Content-Type: application/json

请求字段:

字段类型必填说明
merchantOrderNostring商户唯一订单号,1~128 字符
amountstring大于 0 的金额字符串,最多 2 位小数
currencystring当前使用 INR
payinInterfaceStylestringstandard / extended;默认 extended
notifyUrlstring订单终态通知地址
returnUrlstringHTTPS 跳转地址;平台确认订单支付成功后用于返回商户页面,最长 2048 字符
attachstring商户透传字段,最长 512 字符;通知时原样返回

请求示例:

{
  "merchantOrderNo": "MP-EXAMPLE-001",
  "amount": "500.00",
  "currency": "INR",
  "payinInterfaceStyle": "extended",
  "notifyUrl": "https://merchant.example.com/mc/payin/notify",
  "returnUrl": "https://merchant.example.com/payment/result",
  "attach": "optional"
}

returnUrl 使用说明:

成功响应 data

字段类型说明
orderNostring平台订单号
merchantOrderNostring商户订单号
amountstring订单金额,固定返回两位小数
currencystring订单币种
statusstring创建成功固定为 CREATED
payUrlstring / null可直接公开访问的完整收银台 URL,无需追加 token 或其他参数
payinInterfaceStylestring实际采用的接口样式:standardextended
merchantFeestring / null商户手续费,固定返回两位小数
utrstring / nullUTR;创建时通常为 null
payee_upistring / null收款 UPI / VPA
cash_paramsobject / null扩展收银参数

payinInterfaceStyle 使用说明:

cash_params 非空时包含:

字段类型说明
payee_upistring收款 UPI / VPA
remarkstring支付备注
links.qrstring / nullUPI 二维码内容或支付链接
links.paytmstring / nullPaytm 唤醒链接
links.phonepe_iosstring / nullPhonePe iOS 唤醒链接
links.phonepe_androidstring / nullPhonePe Android 唤醒链接

支付信息使用要求:

重复请求规则:

6. 查询代收订单

GET /open/mc/merchantPayin/query?orderNo=<ORDER_NO>
GET /open/mc/merchantPayin/query?merchantOrderNo=<MERCHANT_ORDER_NO>

Query 严格二选一:

字段说明
orderNo平台订单号,最长 64 字符
merchantOrderNo商户订单号,最长 128 字符

成功响应在创建响应字段基础上增加:

字段说明
createTimeUTC ISO 8601 创建时间
updateTimeUTC ISO 8601 更新时间

代收查询状态:

状态说明
PENDING待处理
PAYING处理中
SUCCESS终态成功
REJECTED终态驳回
FAILED建单失败
EXPIRED已过期
CLOSED已关闭

7. 提交代收 UTR

POST /open/mc/merchantPayin/submitUtr
Content-Type: application/json

请求字段:

字段必填说明
orderNoMC 平台代收订单号;本接口不接受商户订单号
utr12~32 位字母或数字;包含空白、连接符或其他符号时直接返回参数错误,合法值统一转为大写

请求示例:

{
  "orderNo": "<ORDER_NO>",
  "utr": "UTR123456789"
}

成功响应 data

{
  "orderNo": "<ORDER_NO>",
  "merchantOrderNo": "MP-EXAMPLE-001",
  "utr": "UTR123456789",
  "status": "PAYING",
  "verifyStatus": "SUBMITTED"
}

UTR 提交说明:

8. 代收补单

POST /open/mc/merchantPayin/makeup
Content-Type: application/json

请求字段:

字段必填说明
orderNoMC 平台代收订单号;本接口不接受商户订单号
utr12~32 位字母或数字;包含空白、连接符或其他符号时直接返回参数错误,合法值统一转为大写

请求示例:

{
  "orderNo": "<ORDER_NO>",
  "utr": "UTR123456789"
}

成功响应 data

{
  "orderNo": "<ORDER_NO>",
  "merchantOrderNo": "MP-EXAMPLE-001",
  "utr": "UTR123456789",
  "status": "SUCCESS",
  "result": "SUCCESS"
}

补单结果明确失败时返回:

{
  "code": 40306,
  "message": "Makeup failed",
  "data": {
    "orderNo": "<ORDER_NO>",
    "utr": "UTR123456789",
    "result": "FAILED"
  }
}

补单仍在处理时返回:

{
  "code": 1000,
  "message": "处理中,请查询订单",
  "data": {
    "orderNo": "<ORDER_NO>",
    "merchantOrderNo": "MP-EXAMPLE-001",
    "utr": "UTR123456789",
    "status": "PAYING",
    "result": "PROCESSING"
  }
}

补单暂时无法完成时返回:

{
  "code": 40307,
  "message": "Makeup exception, please contact operations",
  "data": {
    "orderNo": "<ORDER_NO>",
    "utr": "UTR123456789",
    "result": "EXCEPTION"
  }
}

补单返回规则:

9. 查询 UPI 是否已存在

GET /open/mc/merchantPayin/upiQuery?upi=receiver%40upi

Query:

字段必填说明
upiUPI ID,例如 receiver@upi

成功响应:

{
  "code": 1000,
  "message": "success",
  "data": {
    "status": "YES"
  }
}

返回值说明:

调用限制:默认同一商户 10 秒内只允许查询一次 UPI;过于频繁返回 40309

10. 查询 UTR 是否已存在

GET /open/mc/merchantPayin/utrQuery?utr=UTR123456789

Query:

字段必填说明
utr单个 UTR,12~32 位字母或数字;包含空白、连字符或其他符号时直接返回 40100,合法值统一转为大写

成功响应:

{
  "code": 1000,
  "message": "success",
  "data": {
    "status": "YES",
    "result": "CURRENT_MERCHANT",
    "orderNo": "PP20260817174707288670"
  }
}

返回值说明:

statusresult 的合法组合如下;除 CURRENT_MERCHANT 外均不返回 orderNo

statusresult含义是否可补单
YESAVAILABLE_FOR_MAKEUP已支付,尚未关联订单
YESCURRENT_MERCHANT已关联当前商户订单
YESOTHER_MERCHANT已被其他商户领取
YESUTR_ORDER_ABNORMALUTR 订单异常
NONOT_FOUND不存在或未支付

调用限制:默认同一商户 10 秒内只允许查询一次 UTR;过于频繁返回 40309

11. 创建代付订单

POST /open/mc/merchantPayout/create
Content-Type: application/json

请求字段:

字段类型必填说明
merchantOrderNostring商户唯一订单号
amountstring两位小数金额字符串
currencystring当前使用 INR
accountNamestring收款人姓名
accountNostringUPI ID 或银行账号
payMethodstringUPI / BANK
platformNamestringBANK 必填银行名称
ifscOrBankCodestringBANK 必填IFSC/银行代码
notifyUrlstring终态通知地址
attachstring商户透传字段,最长 512 字符

UPI 示例:

{
  "merchantOrderNo": "PP-UPI-EXAMPLE-001",
  "amount": "500.00",
  "currency": "INR",
  "accountName": "Test User",
  "accountNo": "receiver@upi",
  "payMethod": "UPI",
  "notifyUrl": "https://merchant.example.com/mc/payout/notify"
}

BANK 示例:

{
  "merchantOrderNo": "PP-BANK-EXAMPLE-001",
  "amount": "500.00",
  "currency": "INR",
  "accountName": "Test User",
  "accountNo": "000000001234",
  "payMethod": "BANK",
  "platformName": "Test Bank",
  "ifscOrBankCode": "TEST0000001",
  "notifyUrl": "https://merchant.example.com/mc/payout/notify",
  "attach": "optional"
}

成功响应 data

{
  "orderNo": "<ORDER_NO>",
  "merchantOrderNo": "PP-UPI-EXAMPLE-001",
  "amount": "500.00",
  "merchantFee": "5.00",
  "currency": "INR",
  "status": "CREATED",
  "freezeAmount": "505.00",
  "utr": null
}

CREATED 只表示平台已受理并完成当前建单步骤,不表示收款人已到账。最终结果以代付查询或验签后的异步通知为准。

重复请求规则:

12. 查询代付订单

GET /open/mc/merchantPayout/query?orderNo=<ORDER_NO>
GET /open/mc/merchantPayout/query?merchantOrderNo=<MERCHANT_ORDER_NO>

Query 严格二选一。

成功响应 data

{
  "orderNo": "<ORDER_NO>",
  "merchantOrderNo": "PP-UPI-EXAMPLE-001",
  "amount": "500.00",
  "merchantFee": "5.00",
  "currency": "INR",
  "status": "PAYING",
  "freezeAmount": "505.00",
  "utr": null,
  "createTime": "2026-07-24T08:00:00.000Z",
  "updateTime": "2026-07-24T08:00:05.000Z"
}

utr 返回规则:

代付查询状态:

状态说明
PENDING待平台处理
PAYING平台处理中
SUCCESS终态成功
REJECTED终态驳回
FAILED平台建单失败

13. 异步通知

异步通知说明:

13.1 代收通知字段

字段类型说明
orderNostring平台订单号
merchantOrderNostring商户订单号
statusstringSUCCESS / REJECTED / EXPIRED
amountstring订单金额
currencystring币种
utrstring/nullUTR;没有时仍发送 null
attachstring创建时传入才返回

代收成功通知示例:

{
  "orderNo": "PI202607240001",
  "merchantOrderNo": "MP-EXAMPLE-001",
  "status": "SUCCESS",
  "amount": "500.00",
  "currency": "INR",
  "utr": null,
  "attach": "optional"
}

13.2 代付通知字段

字段类型说明
orderNostring平台订单号
merchantOrderNostring商户订单号
statusstringSUCCESS / REJECTED
amountstring订单金额
merchantFeestring/null商户手续费
currencystring币种
utrstring/null普通订单为单个 UTR;拆单父单成功时为成功子单 UTR 的 - 连接值;没有时仍发送 null
attachstring创建时传入才返回

代付拆单成功通知示例:

{
  "orderNo": "PO202608210001",
  "merchantOrderNo": "PP-SPLIT-EXAMPLE-001",
  "status": "SUCCESS",
  "amount": "1000.00",
  "merchantFee": "10.00",
  "currency": "INR",
  "utr": "UTR123456789-UTR987654321"
}

代付失败通知示例:

{
  "orderNo": "PO202607240001",
  "merchantOrderNo": "PP-UPI-EXAMPLE-001",
  "status": "REJECTED",
  "amount": "500.00",
  "merchantFee": "5.00",
  "currency": "INR",
  "utr": null
}

通知只包含本节声明的商户业务字段。

13.3 商户 ACK

平台收到以下任一响应即认为通知成功:

  1. HTTP 2xx,纯文本去除首尾空白后不区分大小写等于 success
  2. HTTP 2xx,JSON 的 code 为数字 1000 或字符串 "1000"

示例:

success
{
  "code": 1000,
  "message": "success"
}

14. 公共业务码

code说明
1000成功
40000未分类请求失败
40001鉴权 Header 缺失或非法
40002timestamp 非法或过期
40003签名错误
40004商户不存在、停用或 API 停用
40007nonce 非法或已使用
40100请求参数错误
40101金额错误
40102商户订单号重复或幂等冲突
40201当前商户下订单不存在
40301余额或资金操作失败
40302当前服务暂不可用
40304当前订单不支持此操作
40305UTR 未被接受
40306补单失败;订单已有的 SUCCESS 状态不会被覆盖
40307补单暂时无法完成;请查询订单当前状态并联系运营处理
40308UTR 提交暂时无法完成;请查询订单当前状态后再决定是否重试
40309UPI 或 UTR 查询过于频繁

调用方应按 code 分类处理,不要解析 message 作为程序分支。

15. Node.js 签名示例

以下示例同时适用于请求签名和通知验签:

import crypto from 'node:crypto';

function clean(value) {
  if (
    value === undefined ||
    value === null ||
    (typeof value === 'string' && value.trim() === '') ||
    (typeof value === 'number' && !Number.isFinite(value))
  ) {
    return undefined;
  }
  if (Array.isArray(value)) {
    return value.map(clean).filter(item => item !== undefined);
  }
  if (typeof value === 'object') {
    return Object.keys(value)
      .sort()
      .reduce((result, key) => {
        const item = clean(value[key]);
        if (item !== undefined) result[key] = item;
        return result;
      }, {});
  }
  return value;
}

export function sign({
  method,
  path,
  merchantNo,
  timestamp,
  nonce,
  payload,
  apiKey,
}) {
  const upperMethod = method.toUpperCase();
  const payloadBytes = JSON.stringify(clean(payload) ?? {});
  const payloadSha256 = crypto
    .createHash('sha256')
    .update(payloadBytes, 'utf8')
    .digest('hex');
  const canonicalText = [
    'MCV2-HMAC-SHA256',
    'v2',
    upperMethod,
    path,
    merchantNo,
    String(timestamp),
    nonce,
    payloadSha256,
  ].join('\n');
  return crypto
    .createHmac('sha256', apiKey)
    .update(canonicalText, 'utf8')
    .digest('hex');
}

示例使用说明:

16. 上线前检查