返回网站
目录
聚合支付
聚合支付开发文档
覆盖支付提交、异步回调、查单、退款、商户信息同时兼容旧版彩虹的接口

接口说明

本文档面向接入本平台的商户开发者,说明网关地址、签名鉴权、请求参数、响应结构及业务处理要求

公共网关 https://ceshi.18w.org
默认请求方式 POST
数据格式 application/x-www-form-urlencoded
接入说明

接口金额字段单位为元,建议商户侧固定保留两位小数;所有需要签名的接口请先按签名规则生成签名后再提交

公共规则

网关地址https://ceshi.18w.org
提交数据格式application/x-www-form-urlencoded
字符编码UTF-8
请求方式POST
签名算法MD5

签名规则

安全要求

签名密钥只应保存在服务端,不应出现在浏览器、App 客户端或可公开访问的前端代码中

签名步骤

1. 移除 sign 和 sign_type 字段
2. 移除空值字段
3. 按参数名升序排序
4. 拼接为 key=value&key2=value2 格式
5. 在末尾追加商户密钥
6. 对最终字符串计算 md5
自有协议中的 params 为商户扩展透传字段,下单签名、退款签名和异步通知验签时均不参与签名,无论是否传递或是否为空

示例说明

示例约定

以下示例使用演示密钥 test_key_123456实际接入时请使用商户后台展示的真实 api_key,并保证请求编码为 UTF-8

待签名参数

api_id=10001
mch_order_no=M202606130001
name=test
amount=100.00
notify_url=https://merchant.example.com/notify
return_url=https://merchant.example.com/return
client_ip=127.0.0.1
timestamp=1781260800
method=api
sign_type=MD5
params=merchant_attach

拼接过程

1. 移除 sign_type 字段
2. 自有协议移除 params 字段
3. 按参数名升序排序
4. 拼接得到:
amount=100.00&api_id=10001&client_ip=127.0.0.1&mch_order_no=M202606130001&method=api&name=test&notify_url=https://merchant.example.com/notify&return_url=https://merchant.example.com/return&timestamp=1781260800

5. 追加商户密钥后计算 MD5:
md5("amount=100.00&api_id=10001&client_ip=127.0.0.1&mch_order_no=M202606130001&method=api&name=test&notify_url=https://merchant.example.com/notify&return_url=https://merchant.example.com/return&timestamp=1781260800test_key_123456")

6. 得到 sign:
88b747f0b64dc6f990ffe786ee3c928e

PHP 生成签名

function build_sign(array $params, string $apiKey, bool $excludeParams = true): string
{
    unset($params['sign'], $params['sign_type']);

    if ($excludeParams) {
        unset($params['params']);
    }

    ksort($params);

    $pairs = [];
    foreach ($params as $key => $value) {
        if ($value === '' || $value === null || is_array($value)) {
            continue;
        }
        $pairs[] = $key . '=' . $value;
    }

    return md5(implode('&', $pairs) . $apiKey);
}

PHP 验签示例

$apiKey = 'test_key_123456';
$params = $_POST;
$merchantSign = $params['sign'] ?? '';
$systemSign = build_sign($params, $apiKey, true);

if (!hash_equals($systemSign, $merchantSign)) {
    exit('sign error');
}

注意事项

1. sign 字段必须使用小写 MD5 字符串
2. sign 和 sign_type 永远不参与签名
3. 自有协议 params 永远不参与签名,无论下单请求、退款请求还是异步通知
4. 自有协议统一下单的 method 必填并参与签名
5. 空字符串和 null 不参与签名
6. 金额建议商户侧按字符串处理,例如 100.00,避免浮点数导致签名不一致
7. 验签时必须使用原始接收到的字段值,不要先做 URL 解码之外的格式化、四舍五入或类型转换

支付方式列表

支付方式编码

下单接口的 type 字段需使用下表中的编码后台禁用或通道未配置的支付方式可能无法创建订单

方式编码

编码 说明
alipay 支付宝
wxpay 微信支付
qqpay QQ钱包

设备类型列表

设备类型编码

下单接口的 device字段需使用下表中的编码,系统将根据对应设备类型选择最优通道

类型编码

编码 说明
pc pc(电脑浏览器)
mobile mobile(手机浏览器)
android android(安卓应用)
ios ios(苹果应用)
qq QQ内置浏览器
wechat 微信内置浏览器
alipay 支付宝客户端
mini 小程序

对接方式列表

对接方式编码

下单接口的method字段需使用下表中的,系统将根据不同的对接方式返回不同的内容

对接方式

对接方式 说明
api 传入此值将返回json格式数据,商户可根据返回的支付数据自行安排发起支付的方式
submit 传入此值可用于用户前台直接发起支付,使用form表单跳转或拼接成url跳转

统一下单接口

请求地址 https://ceshi.18w.org/payment/submit
请求方式 POST
接口说明

统一下单接口用于创建支付订单,商户订单号必须保持唯一;重复提交同一订单号时只能沿用首次请求的对接方式,跨 API/submit 模式将被拒绝

请求参数

字段名 参数 必填 参与签名 说明
商户对接ID api_id 是 是 商户对接ID
支付方式 type 否 传入非空时参与 支付方式,详见支付方式列表;不传时系统返回收银台地址,由用户选择支付方式
商户订单号 mch_order_no 是 是 商户订单号,格式为1至64位字母、数字、下划线或短横线;同一商户内必须唯一
异步回调地址 notify_url 是 是 支付订单异步回调地址
同步回调地址 return_url 是 是 支付订单页面跳转回调地址
当前时间戳 timestamp 是 是 10位秒级Unix时间戳,默认允许300秒误差,具体以系统配置为准
付款用户IP client_ip 是 是 实际付款用户的合法IPv4或IPv6地址,不能固定填写商户服务器IP
商品名称 name 是 是 如超过64个字节会自动截取
商品金额 amount 是 是 单位元,金额文本最多64字符;仅支持十进制整数或小数,超出两位的小数截断、不四舍五入,截断后须大于0。按传入金额原文签名,建单金额统一为两位小数;例如0012.349按原文签名、按12.34建单。金额及计费结果不得超出数据库字段容量,仍受通道金额限制
业务扩展参数 params 否 否 没有请留空,回调时将原样传入
设备类型 device 否 传入非空时参与 用户设备类型,详见设备类型列表
对接方式 method 是 是 对接方式,仅允许小写api或submit,详见对接方式列表
请求签名 sign 是 否 按签名规则生成的小写MD5字符串
签名方式 sign_type 是 否 签名方式,固定传入MD5
商户后台启用API IP白名单后,仅校验 method=api 请求的实际HTTP来源IP;client_ip 始终表示付款用户IP,两者用途不同,接口无需传入额外的服务器IP字段

响应说明

API 模式响应

当 method=api 时,系统返回 JSON;自有协议统一使用 data.url 承载支付入口,并通过 data.method 标识链接类型,不返回彩虹协议中的 payurl、qrcode、urlscheme 字段

字段 类型 说明
codeint1 表示发起成功,0 表示发起失败
msgstring响应提示,成功时通常为 发起成功!
timeint系统响应时间戳,单位秒
data.order_nostring平台订单号,后续查单、支付状态追踪可使用该字段
data.mch_order_nostring商户订单号,即请求中的 mch_order_no
data.urlstring支付入口地址可能是系统支付页、收银台,也可能是上游直连支付链接
data.methodstring链接处理方式,当前支持 jump、qrcode、scheme

链接处理方式

值处理方式说明
jump浏览器跳转商户前端可直接跳转到 data.url系统支付页、收银台默认均为该类型
qrcode二维码展示商户前端应根据 data.url 生成二维码给用户扫码支付
schemeURL Scheme 拉起商户前端可使用 data.url 拉起 App、小程序或钱包支付环境

成功示例

{
    "code": 1,
    "msg": "发起成功!",
    "time": 1781260800,
    "data": {
        "order_no": "20260613123015000001",
        "mch_order_no": "M202606130001",
        "url": "https://pay.example.com/payment/order/20260613123015000001",
        "method": "jump"
    }
}

失败示例

{
    "code": 0,
    "msg": "签名错误",
    "time": 1781260800,
    "data": null
}

业务说明

1. mch_order_no 在同一商户内唯一,不同商户可以使用相同商户订单号
2. 重复请求仅在接入协议、金额、商品名、支付类型、请求方式、付款IP、通知地址、返回地址和设备类型均与首次提交一致时复用原订单
3. 未指定支付方式或未确定可用通道时,data.url 可能返回系统收银台地址,由用户选择支付方式
4. 当 method=submit 时,该接口用于浏览器前台提交,成功时直接跳转支付页面,失败时展示 HTML 提示页,不返回上述 JSON 结构

订单查询

请求地址 https://ceshi.18w.org/payment/query
请求方式 POST
返回格式 JSON
接口说明

该接口只读取当前商户的本地订单,不请求上游、不修改订单状态;可查询本商户通过任意接入协议创建的订单

公共参数

参数必传参与签名说明
api_id是是商户号
mode是是single 查询单笔,list 查询历史列表
timestamp是是10位秒级 Unix 时间戳
sign是否请求签名
sign_type是否固定为 MD5
除 sign 和 sign_type 外,实际传入的所有查询参数都参与签名;查询响应不附加响应签名,请通过 HTTPS 调用

单笔查询参数

参数必传参与签名说明
order_no二选一传入时参与平台系统订单号
mch_order_no二选一传入时参与商户订单号
两个订单号同时传入时必须指向同一笔订单,否则返回订单不存在
api_id=10001
mode=single
mch_order_no=M202606130001
timestamp=1781260800
sign_type=MD5
sign=请求签名

历史列表参数

参数必传参与签名说明
cursor否传入时参与下一页游标,最多256字符,原样使用上一次响应的 data.next_cursor,不可跨商户使用
limit否传入时参与每页1至100条,默认20条
status否传入时参与订单状态:0未付款、1已支付、2已退款、3已超时、5已冻结;仅支持这些值,省略则不筛选
notify_status否传入时参与(含0)商户异步通知状态:0未通知、1通知成功、2通知失败、3多次通知失败且已停止自动重试;省略则不筛选,可与订单状态组合使用
start_time否传入时参与创建时间起点,10位 Unix 时间戳
end_time否传入时参与创建时间终点,10位 Unix 时间戳
按订单创建时间筛选,起止时间均包含边界。都不传时查询首次请求时刻向前24小时;仅传 end_time 时向前补24小时;仅传 start_time 时向后补24小时,终点不超过首次请求时刻。起点不得晚于终点,每个查询窗口最长7天(604800秒);可查询更早的历史窗口,不限于最近7天
列表按创建时间倒序,同秒订单按ID倒序。游标固定首次解析的时间窗口及状态筛选,翻页可以省略这些条件,重复传入时必须与原条件一致;limit 可调整。每页使用新的 timestamp 重新签名。修改条件请移除游标重新查询;旧版游标会提示重新查询。游标不冻结订单的实时状态
api_id=10001
mode=list
limit=20
status=1
notify_status=2
start_time=1780656000
end_time=1781260800
timestamp=1781260800
sign_type=MD5
sign=请求签名

订单字段

字段类型说明
order_nostring平台系统订单号
mch_order_nostring商户订单号
upstream_order_nostring|null上游支付平台订单号
typestring|null支付方式
namestring|null商品名称
amountstring|null订单金额
real_amountstring|null实际支付金额
refund_amountstring|null退款金额
statusint0未付款、1已支付、2已退款、3已超时、5已冻结;单笔与列表语义一致
status_textstring订单状态文字
notify_statusint|null0未通知、1通知成功、2通知失败、3多次通知失败且已停止自动重试;与支付状态独立,已支付不代表通知成功
created_atint|null订单创建时间
paid_atint|null支付完成时间
pay_durationint|null支付耗时,单位秒

响应结构

单笔:data.order 为订单字段对象

列表:
data.items        当前页订单数组
data.next_cursor  下一页游标,无下一页时为 null
data.has_more     是否还有下一页
data.limit        本次每页数量

列表接口不返回 total,也不执行总数统计
单笔查询每商户最多120次/分钟,列表查询每商户最多30次/分钟;超过限制返回 code=0

异步通知

通知投递规则

支付完成或自有协议订单最终退款成功后,系统会对商户下单时传入的 notify_url 进行POST请求。首次通知不计入补发次数;首次通知失败后最多自动补发10次,补发间隔依次为5秒、15秒、30秒、60秒,超过前四次后固定每60秒补发一次。首次通知、自动补发和后台人工重新通知的参数、签名与成功响应完全一致,商户处理成功时需返回 HTTP 2xx,并输出纯文本 succeed

支付成功通知

参数 是否必传 参与签名 说明
api_id 是 是 商户号
notify_type 是 是 通知类型,支付成功固定为 payment
order_no 是 是 平台订单号
mch_order_no 是 是 商户订单号
type 是 是 支付方式编码
name 是 是 商品名称
amount 是 是 商户提交订单金额,单位元,字符串格式
real_amount 是 是 实际支付金额,单位元,字符串格式
status 是 是 支付成功固定为 succeed
params 是 否 商户下单传入的扩展参数,没有则为空;该字段不参与签名
sign 是 否 回调签名,按签名规则生成,但排除 params
sign_type 是 否 签名类型,固定为 MD5

支付通知处理建议

1. 商户系统收到通知后先校验 sign
2. 验签时移除 sign、sign_type、params,再按签名规则计算
3. 以 mch_order_no 做幂等处理,同一商户订单号重复通知时只处理一次
4. 业务处理成功后输出 succeed,不要输出 JSON、HTML 或其它字符

退款成功通知

退款通知仅在退款最终成功后发送,固定携带 notify_type=refund;仅自有协议订单发送,彩虹兼容协议订单不发送退款通知
参数 是否必传 参与签名 说明
api_id 是 是 商户号
notify_type 是 是 通知类型,退款成功固定为 refund
order_no 是 是 平台原支付订单号
mch_order_no 是 是 商户原支付订单号
refund_no 是 是 退款单号,用于退款通知幂等;接口退款时由商户提交,后台或商户页面退款时由平台生成
order_amount 是 是 原支付订单金额,单位元,两位小数字符串
refund_amount 是 是 本次退款金额,单位元,两位小数字符串
status 是 是 退款成功固定为 succeed
complete_time 是 是 退款最终完成时间,10位 Unix 时间戳字符串
sign 是 否 退款通知签名,按签名规则生成
sign_type 是 否 签名类型,固定为 MD5
退款通知除 sign、sign_type 外,其余字段全部参与签名;退款通知不包含 params

退款通知处理建议

1. 退款接口成功响应与退款异步通知相互独立,接口响应不能替代异步通知
2. 收到通知后先移除 sign、sign_type,再使用其余全部字段验签
3. 核对 order_no、mch_order_no、order_amount 和 refund_amount 是否与本地记录一致
4. 以 refund_no 做幂等处理,同一退款单号重复通知时只完成一次退款业务
5. 通知采用至少一次投递,业务处理成功后返回 HTTP 2xx 和纯文本 succeed

接口退款

请求地址 https://ceshi.18w.org/payment/refund
请求方式 POST
返回格式 JSON
接口说明

接口退款用于商户系统对自有协议创建的已支付订单发起退款

请求参数

参数 是否必传 参与签名 说明
api_id 是 是 商户号
order_no 二选一 传入时参与 系统订单号,即统一下单成功返回的 data.order_no
mch_order_no 二选一 传入时参与 商户订单号,即统一下单时传入的 mch_order_no
refund_no 是 是 商户退款单号,最长 64 个字符;用于幂等识别
amount 是 是 退款金额,单位元,最多两位小数,必须大于 0 且不能大于订单实付金额
timestamp 是 是 10 位 Unix 时间戳,默认允许 300 秒时间窗口,具体以系统配置为准
params 否 否 商户扩展透传字段,不参与签名,无论是否传递或是否为空
sign 是 否 请求签名,按签名规则生成
sign_type 是 否 签名类型,固定为 MD5
注意:order_no 和 mch_order_no 至少传入一个;如果两个都传入,系统会同时校验两个字段必须指向同一笔订单

退款签名字段

参与签名字段:
api_id
order_no(传入时参与)
mch_order_no(传入时参与)
refund_no
amount
timestamp

不参与签名字段:
sign
sign_type
params

请求示例

api_id=10001
order_no=20260613123015000001
mch_order_no=M202606130001
refund_no=R202606130001
amount=100.00
timestamp=1781260800
sign_type=MD5
params=merchant_refund_attach
sign=42ed3b28194b6945c124a1661ba46acf

签名拼接示例

1. 移除 sign、sign_type、params
2. 移除空值字段
3. 按参数名升序排序
4. 拼接得到:
amount=100.00&api_id=10001&mch_order_no=M202606130001&order_no=20260613123015000001&refund_no=R202606130001&timestamp=1781260800

5. 追加商户密钥后计算 MD5:
md5("amount=100.00&api_id=10001&mch_order_no=M202606130001&order_no=20260613123015000001&refund_no=R202606130001&timestamp=1781260800test_key_123456")

6. 得到 sign:
2166b4e6dbea9efec1e1964bf495faa6

返回字段

字段 类型 说明
codeint1 表示成功,0 表示失败
msgstring退款成功或失败原因
timeint响应时间戳
data.order_nostring系统订单号
data.mch_order_nostring商户订单号
data.refund_nostring商户退款单号
data.amountstring退款金额
data.statusstring退款成功固定为 succeed

成功示例

{
    "code": 1,
    "msg": "退款成功",
    "time": 1781260800,
    "data": {
        "order_no": "20260613123015000001",
        "mch_order_no": "M202606130001",
        "refund_no": "R202606130001",
        "amount": "100.00",
        "status": "succeed"
    }
}

失败示例

{
    "code": 0,
    "msg": "当前订单不是已支付状态,不能退款",
    "time": 1781260800,
    "data": null
}

业务说明

1. 该接口只处理本系统自有协议订单,不处理彩虹兼容协议订单
2. 同一订单当前只允许退款一次,支持全额退款或部分退款
3. 重复提交同一 order_no、refund_no、amount 且历史退款成功时,系统会按幂等成功返回
4. 如果订单已退款但 refund_no 或 amount 与历史退款不一致,系统会拒绝重复退款
5. 退款金额按字符串处理,建议固定保留两位小数
6. 支付插件支持自动退款时,系统会先请求上游支付平台;上游返回失败时本次退款失败
7. 支付插件不支持自动退款或通道信息缺失时,允许仅执行系统内退款,不会向上游支付平台发起退款
8. 上游支付平台退款成功后,系统会先记录上游成功状态,再完成系统内退款;系统内处理失败时重试不会再次请求上游
9. 退款接口成功响应与退款异步通知相互独立,商户应以退款成功通知完成本地最终业务

彩虹相关接口说明

接入说明

本系统兼容彩虹易支付V1对接方式,涵盖以下功能:【页面跳转支付】、【API接口支付】、【支付结果通知】、【查询商户信息】、【查询结算记录】、【查询单个订单】、【查询单个订单】、【提交订单退款】

常见问题

排错建议

如果接口返回参数错误、签名错误或回调失败,请优先核对请求入口、提交方式、签名字段、时间戳和回调响应内容

为什么提示“本系统接口请使用 /payment/submit 接入”?

通常是把彩虹兼容协议的 pid 参数提交到了自有协议入口自有协议统一下单必须使用 api_id,并通过 /payment/submit 以 POST 方式提交

  • 自有协议字段:api_id、mch_order_no、amount
  • 彩虹兼容协议字段:pid、out_trade_no、money
  • 两个协议的字段不要混用

为什么一直返回签名错误?

签名错误多半不是密钥错误,而是参与签名的字段范围不一致系统会按字段名升序排序,排除 sign、sign_type 和空值字段后再追加商户密钥计算 MD5

  • 自有协议中的 params 永远不参与签名
  • 统一下单的 method 必填并参与签名,且只能使用小写 api 或 submit
  • type、device 这类可选字段只要传入,就要参与签名
  • 金额建议固定为字符串,例如 10.00,不要用浮点数直接拼接

为什么提示 timestamp 格式错误或请求已过期?

timestamp 必须是 10 位秒级时间戳,并且会参与签名Java、JavaScript 等语言常见的毫秒时间戳是 13 位,不能直接提交

  • 正确示例:1718000000
  • 错误示例:1718000000000
  • 如果时间戳正确仍提示过期,请校准商户服务器时间,建议开启 NTP

method 和 type 有什么区别?

method 是对接方式,决定系统如何返回支付拉起结果;type 是支付方式,决定使用支付宝、微信、QQ 等哪一种支付类型

  • method=api:适合服务端请求,返回 JSON
  • method=submit:适合浏览器表单跳转,可能直接进入支付页面
  • 相同商户订单号不能在两种对接方式之间切换
  • type=alipay、wxpay、qqpay:表示支付方式

API 下单成功后应该读取哪个字段?

自有协议统一下单成功时,支付链接在 data.url,链接类型在 data.method不要按彩虹协议去读取 payurl、qrcode 或 urlscheme

  • data.method=jump:跳转链接
  • data.method=qrcode:二维码内容或二维码链接
  • data.method=scheme:客户端唤起链接

为什么异步回调一直重试?

自有协议支付回调处理成功后,商户系统必须原样返回 succeed不要返回 JSON、HTML、空格、换行或调试信息,否则系统会认为商户没有成功接收通知

  • 先验签,再校验订单号和金额,最后更新本地订单
  • 同一笔订单可能收到多次通知,商户系统必须按 mch_order_no 做幂等
  • 同步跳转只用于页面展示,不能作为入账依据

回调里的 amount 和 real_amount 应该如何使用?

amount 是商户下单金额,real_amount 是系统实际支付金额商户收到回调后,应结合本地订单记录做金额校验,确认订单号、金额和状态都匹配后再处理发货或入账

  • 不要只判断 status=succeed 就更新订单
  • 不要跳过签名校验
  • 金额比较时建议保留两位小数字符串比较

接口退款时 order_no 和 mch_order_no 应该传哪个?

order_no 是平台系统订单号,mch_order_no 是商户订单号接口退款时二者至少传入一个;如果两个都传入,系统会同时校验它们必须指向同一笔订单

  • 商户系统更容易保存和使用 mch_order_no
  • 如果传入 order_no 或 mch_order_no,对应字段需要参与退款签名
  • 同一笔退款请固定使用同一个 refund_no,不要每次重试都换新退款单号

为什么退款金额格式错误?

退款金额字段 amount 必须为大于 0 的金额字符串,最多保留两位小数,且不能大于原订单实际支付金额

  • 正确示例:1、1.00、10.50
  • 错误示例:1.001、0、-1.00
  • 一个订单只能成功退款一次,请做好商户侧退款状态记录

测试支付成功是否代表正式商户一定可用?

测试支付只验证系统配置的测试商户或指定测试通道是否可用,不代表所有正式商户、所有支付方式、所有通道都可用

  • 正式接入前仍需检查商户状态、支付方式配置、通道分配和回调地址
  • 前台测试支付只展示测试商户可用的支付方式
  • 正式环境请使用商户自己的 api_id 和 api_key

为什么复制 Demo 后仍然请求失败?

Demo 中的网关地址、商户号、密钥、回调地址都是占位配置,复制后必须先替换成商户后台中的真实信息

  • api_key 只能保存在服务端,不能写入前端页面或 App 客户端
  • 回调地址必须能被平台服务器公网访问
  • 如果本地调试无法接收回调,可先使用可公网访问的测试域名或内网穿透工具

DEMO 下载

接入示例

Demo 包含 PHP 与 Java 版本的自有协议接入示例,覆盖统一下单、接口退款、异步回调验签和同步跳转展示