Skip to content

商户收款接口 ​

接口地址:https://api.urpye.com

商户密钥由平台生成并确认配置后启用,不随请求发送。通道编码由平台提供,下单必填。以下 UUID 和密钥 demo_merchant_secret_replace_me 仅用于示例。

1. 创建收款 ​

http
POST /receipts
Content-Type: application/json

请求示例 ​

bash
curl --request POST 'https://api.urpye.com/receipts' \
  --header 'Content-Type: application/json' \
  --data '{
    "merchantId": "123456789012345678",
    "merchantTradeNo": "ORDER_20260727_001",
    "channelCode": "f7ce8569-ae9b-4b0b-8d31-90e4fbd88f2a",
    "method": "alipay",
    "amount": "2000",
    "productName": "AI Credits",
    "productDescription": "Purchase 1000 credits",
    "notifyUrl": "https://merchant.example.com/payment/notify",
    "timestamp": 1785110400,
    "sign": "32b061d61b06c2a5571718ab8cef6897af79c3080801800b39f87620fce405fd"
  }'

替换商户 ID、通道编码、密钥和通知地址,使用当前时间戳重新计算签名。请求时间与服务器相差不得超过 300 秒。

参数说明 ​

字段类型必填说明
merchantIdstring是平台分配的商户 ID
merchantTradeNostring是商户订单号,同一商户下唯一,最多 128 字符
channelCodestring是平台提供的通道编码,36 字符、小写、带连字符的 UUID v4
methodstring是当前仅支持 alipay
amountstring是正整数金额,单位为分;2000 表示 20 元
productNamestring是商品名称,最多 255 字符
productDescriptionstring否商品描述,最多 2048 字符
notifyUrlstring是公网 HTTP/HTTPS 通知地址,最多 2048 字符
timestampinteger是正整数 Unix 时间戳,单位为秒
signstring是64 位 HMAC-SHA256 十六进制签名

成功响应 ​

首次创建返回 HTTP 201;相同订单号和业务参数、原链接有效时,返回 HTTP 200。

json
{
  "code": 0,
  "message": "success",
  "data": {
    "merchantTradeNo": "ORDER_20260727_001",
    "channelCode": "f7ce8569-ae9b-4b0b-8d31-90e4fbd88f2a",
    "amount": "2000",
    "url": "https://qr.alipay.com/sample",
    "sign": "2f168d5334959156729bc18d734a1be947a7582e07f3af96be4f010183ea7c9d"
  }
}

验签并核对订单号、通道及金额后打开 data.url。链接有效期约 3–5 分钟,支付结果通过通知或查单确认。

2. 签名 ​

创建及查询请求必须签名,创建响应 data 和通知必须验签:

  1. 排除 sign 和值为 null 的字段,保留空字符串。
  2. 按字段名排序,生成紧凑 JSON;保留原始值及类型,中文不转义。
  3. 请求原文为 HTTP方法 + "\n" + 路径 + "\n" + JSON;方法大写,路径不包含域名和查询串。
  4. 创建响应和通知的原文只包含上述 JSON。使用商户密钥计算 UTF-8 HMAC-SHA256,输出 64 位小写十六进制。

GET 参数全部按解码后的字符串签名,只加入实际传递的参数,不补默认值;查询参数不能重复。POST 保持 JSON 类型,timestamp 为整数。URL 编码在签名完成后进行。

python
import hashlib
import hmac
import json
import re


def signing_content(payload):
    return json.dumps(
        {key: value for key, value in payload.items() if key != "sign" and value is not None},
        ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False,
    )


def create_sign(payload, secret):
    return hmac.new(secret.encode("utf-8"), signing_content(payload).encode("utf-8"), hashlib.sha256).hexdigest()


def create_request_sign(payload, secret, method, path):
    content = f"{method.upper()}\n{path}\n{signing_content(payload)}"
    return hmac.new(secret.encode("utf-8"), content.encode("utf-8"), hashlib.sha256).hexdigest()


def verify_sign(payload, secret):
    sign = payload.get("sign")
    return (
        isinstance(sign, str)
        and re.fullmatch(r"[a-fA-F0-9]{64}", sign) is not None
        and hmac.compare_digest(create_sign(payload, secret), sign.lower())
    )


# 创建:payload["sign"] = create_request_sign(payload, secret, "POST", "/receipts")
# 查询:params["sign"] = create_request_sign(params, secret, "GET", "/receipts/list")
# 创建响应:verify_sign(response["data"], secret)
# 通知:verify_sign(notification, secret)

3. 收款结果通知 ​

http
POST {notifyUrl}
Content-Type: application/json
Accept: text/plain
json
{
  "merchantTradeNo": "ORDER_20260727_001",
  "channelCode": "f7ce8569-ae9b-4b0b-8d31-90e4fbd88f2a",
  "method": "alipay",
  "amount": "2000",
  "status": "paid",
  "timestamp": 1785110480,
  "sign": "03a2d5c24d8810d39ee33996610a42262346dc503cd54ded29aa70c3a226588b"
}

channelCode 为订单实际使用的通道;amount 单位为分;status 为 paid(已支付)或 closed(已关闭);timestamp 为结果确认时间,单位为秒。

通知验签使用当前商户密钥,不对通知时间戳应用 300 秒请求时效限制。密钥重置后,未送达通知会使用新密钥重新签名。

验签、核对订单及金额,按商户订单号幂等处理后返回:

http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

success
  • HTTP 2xx + 纯文本 success 表示接收成功,忽略大小写和首尾空白。
  • 超时 10 秒,不跟随重定向;自动投递最多 5 次,重复通知须幂等处理。
  • 链接到期不自动关闭订单,也不发送关闭通知。

4. 错误与重试 ​

错误示例(HTTP 401):

json
{
  "code": 401,
  "msg": "签名校验失败"
}
HTTP 状态码说明
400参数或金额不支持,通道不存在、停用或与支付方式不匹配
401签名错误或请求已过期
403商户停用、密钥未确认或无权限
404商户或订单不存在
409订单参数冲突或暂不可创建
410原订单已关闭或链接到期
422JSON 或字段格式错误
429请求频繁,按 Retry-After 等待
500服务异常或创建结果未确认
501支付方式暂不支持
502创建收款被拒绝

HTTP 422 的错误位于 detail 数组;HTTP 502 的错误说明位于 msg.message。

超时后先查单。同一订单号重试须保持通道和其他业务参数一致,更换通道返回 409;可更新 timestamp 和 sign,结果未确认时不要换号下单。

5. 商户订单列表 ​

http
GET /receipts/list

查询参数 ​

字段类型必填说明
merchantIdstring是平台分配的商户 ID
channelCodestring否按通道编码精确筛选,格式同下单参数
pageNuminteger否页码,默认 1
pageSizeinteger否每页数量,默认 20,范围 1–100
merchantTradeNostring否商户订单号,精确匹配
statusstring否订单状态,见下表
beginTimestring否创建时间起点,包含;带时区的 ISO 8601 时间
endTimestring否创建时间终点,不包含;带时区的 ISO 8601 时间
timestampstring是当前 Unix 秒级时间戳,查询参数按字符串签名
signstring是64 位 HMAC-SHA256 签名

查单无需额外 Header。时间示例:2026-10-02T00:00:00+08:00,URL 中的 + 需编码为 %2B;同时传入起止时间时须满足 beginTime < endTime。

请求示例 ​

bash
curl --get 'https://api.urpye.com/receipts/list' \
  --data-urlencode 'merchantId=123456789012345678' \
  --data-urlencode 'pageNum=1' \
  --data-urlencode 'pageSize=20' \
  --data-urlencode 'timestamp=1785110400' \
  --data-urlencode 'sign=ab7362ab94709932ddb8fd7e8bb5eea95a48722aa63b2e899e9f7db9dfd28522'

成功响应 ​

HTTP 200:

json
{
  "code": 0,
  "message": "success",
  "data": {
    "rows": [
      {
        "orderId": "364070014577283072",
        "merchantTradeNo": "ORDER_20260727_001",
        "channelCode": "f7ce8569-ae9b-4b0b-8d31-90e4fbd88f2a",
        "method": "alipay",
        "amount": "2000",
        "productName": "AI Credits",
        "status": "awaiting_payment",
        "createTime": "2026-10-02T02:00:00.000Z",
        "paidAt": null,
        "closedAt": null
      }
    ],
    "pageNum": 1,
    "pageSize": 20,
    "total": 1,
    "hasNext": false
  }
}

rows 为当前页订单,total 为匹配总数,hasNext 表示是否有下一页。amount 单位为分,时间使用 UTC(Z);订单 ID 使用字符串。

状态说明
creating创建中
awaiting_payment待支付
paid已支付
closed已关闭
creation_failed创建失败
creation_unknown创建结果未确认
authorization_required授权不可用,创建未完成

单笔查单 ​

bash
curl --get 'https://api.urpye.com/receipts' \
  --data-urlencode 'merchantId=123456789012345678' \
  --data-urlencode 'merchantTradeNo=ORDER_20260727_001' \
  --data-urlencode 'timestamp=1785110400' \
  --data-urlencode 'sign=c717eff6236fde00038d31fdc2008253f5b4066c6256bd2552f46852b8939da9'

也支持 GET /receipts/{orderId},传入 merchantId、timestamp 和 sign,使用实际路径(例如 /receipts/364070014577283072)签名。单笔查询无需传通道编码;响应中 channelCode 为实际通道,requestKey 为商户订单号。所有商户接口和通知中的 amount 均为分字符串,例如 "2000" 表示人民币 20 元。