DEVELOPER API码支付 · 兼容易支付协议

从签名到回调,
按这份文档一次接通。

适用于独立商城、发卡系统、订单系统及其他服务端应用。本文档按真实接口调用顺序编排,包含完整参数、MD5 签名、回调验签、查单与排错方法。

先准备好商户 PID、支付对接密钥和至少一个已启用通道

凭证请从“商户中心 → API 配置”复制。签名使用的是支付对接密钥(pay_key),不要使用登录密码或挂机软件密钥。

01

QUICK START

接入流程

推荐由你的服务端完成签名和下单。浏览器、APP、小程序只接收服务端返回的收银台地址,绝不能持有支付密钥。

  1. 1
    获取凭证

    复制商户 PID 与支付对接密钥,启用套餐和支付通道。

  2. 2
    生成签名

    服务端按 ASCII 键名排序,拼接参数与密钥并计算 MD5。

  3. 3
    创建订单

    跳转 submit.php,或请求 mapi.php 获取支付链接。

  4. 4
    处理回调

    验签、核对金额和订单状态,幂等更新后返回纯文本 success

接口约定
  • 协议:HTTPS
  • 编码:UTF-8
  • 请求:application/x-www-form-urlencoded
  • 金额单位:人民币元
  • 签名:MD5(32 位小写)
02

AUTHENTICATION

商户凭证

pid商户 PID

平台分配的对接标识,以后台显示值为准,当前通常为 M 开头。

pay_key支付对接密钥

只用于支付签名和回调验签。密钥重置后,旧签名立即失效。

密钥安全红线

不要写进 HTML、JavaScript、APP 安装包、公开仓库或访问日志;不要将 key 返回给前端。生产环境请通过环境变量或密钥管理服务读取。

03

SIGNATURE

MD5 签名算法

  1. 排序

    把本次实际发送的全部参数按参数名 ASCII 升序排列。

  2. 过滤

    排除 signsign_type、路由参数 a/c/m/s 以及值为空字符串的参数。

  3. 拼接

    key=value& 连接;值保持原样,签名前不要 URL 编码。

  4. 加密

    在参数串末尾直接追加支付对接密钥,计算 32 位小写 MD5。

验签使用表单解析后的原始字段值

服务端以 application/x-www-form-urlencoded 解析后的值计算签名。验签前不会执行 HTML 转义、去除首尾空格、大小写转换、金额格式重写、JSON 转义或二次 URL 编解码。notify_urlreturn_url 可以携带查询参数,其中的原始 & 必须参与签名;不要改成 &

完整签名规则
  • 排除 signsign_typeacms
  • 排除值为''或 null 的字段,其他已发送字段全部参与。
  • 按参数名升序排列,按 参数名=原始参数值 拼接并以 & 连接。
  • 参数串末尾直接追加 pay_key,计算 32 位小写 MD5。
  • 客户端必须先计算签名,再用 http_build_query 或等价方法编码并发送。
待签名字符串money=0.01&name=测试商品&...&type=alipayYOUR_PAY_KEY末尾密钥前不增加 &key=,而是直接拼接密钥。
签名一致性

可选参数只要非空且被发送,就必须参与签名。请求金额用什么字符串签名就发送什么字符串;回调中的 money 固定为两位小数,例如 1.00

固定签名测试向量

先用下面的假凭证验证你的签名函数。只有得到相同结果,再替换成真实 PID 和密钥发起请求;该测试向量不能用于真实下单。

三种语言都必须得到同一 MD5
pay_key = test_pay_key_20260813
pid = M1234567890
type = alipay
out_trade_no = ORDER202608130001
notify_url = https://shop.example.com/pay/notify?channel=alipay&version=2
return_url = https://shop.example.com/pay/return?order=ORDER202608130001&source=pay
name = 测试订单
money = 1.00

expected_sign = beddd35092c3afea54c5218de0872502
04

PAGE PAYMENT

页面跳转支付

POST / GEThttps://pay.1kexiu.xyz/submit.php

适合网页商城和发卡系统。建议用服务端生成的自动提交表单将用户浏览器跳转到此接口;成功后进入平台收银台,响应是 HTML,不是 JSON。

请求参数

参数必填类型说明
pid必填String商户 PID,以后台 API 配置页显示值为准。
type必填String支付分类:alipaywxpayqqpay;需有对应启用通道。
out_trade_no必填String商户订单号,只允许字母、数字及 . _ - |,同一订单请保持唯一。
notify_url必填String服务端异步通知地址,必须可被公网访问;允许携带查询参数,原始 & 参与签名。
return_url必填String付款后的浏览器跳转地址;允许携带查询参数,不能代替异步通知。
name必填String商品或订单标题。
money必填String订单金额,单位元,必须大于 0,建议固定两位小数。
param选填String业务扩展参数,付款回调时原样返回;不要放敏感信息。
sign必填String按本文算法生成的 32 位小写 MD5。
sign_type必填String固定为 MD5
HTML 自动提交示例
<form id="payForm" action="https://pay.1kexiu.xyz/submit.php" method="post">
  <input type="hidden" name="pid" value="YOUR_PID">
  <input type="hidden" name="type" value="alipay">
  <input type="hidden" name="out_trade_no" value="ORDER_202608130001">
  <input type="hidden" name="notify_url" value="https://your-site.example/pay/notify">
  <input type="hidden" name="return_url" value="https://your-site.example/pay/return">
  <input type="hidden" name="name" value="测试商品">
  <input type="hidden" name="money" value="0.01">
  <input type="hidden" name="sign" value="SERVER_GENERATED_SIGN">
  <input type="hidden" name="sign_type" value="MD5">
</form>
<script>document.getElementById('payForm').submit();</script>
SERVER_GENERATED_SIGN 只是占位符

不能把它原样提交。必须先在你的服务端按本文算法计算真实 sign,再渲染自动提交表单;可直接复用后文 PHP/Node.js/Python 的 makeSign 函数。

05

API PAYMENT

API 下单

POSThttps://pay.1kexiu.xyz/mapi.php

适合服务端请求后自行处理支付链接或二维码。请求参数与 页面跳转支付一致,推荐使用 POST 表单编码。

return_url 在新版中必须传

旧版文档曾把它标为选填,但新版核心下单服务会校验该字段;缺少时会返回“回调地址(return_url)不能为空”。

兼容参数

参数必填说明
clientip选填付款用户 IP,兼容易支付客户端;发送非空值时必须参与签名。
device选填pcmobilewechatalipayqq;发送时参与签名。

成功响应

后台“API 返回模式”决定主要字段:payurl 为支付/收银台地址,qrcode 为可生成二维码的内容。接入端应兼容两者,优先处理实际非空字段。

支付链接模式
{
  "code": 1,
  "msg": "下单成功",
  "trade_no": "5090058146920009728",
  "payurl": "https://pay.1kexiu.xyz/gateway/Submit/pay?trade_no=..."
}
二维码模式
{
  "code": 1,
  "msg": "下单成功",
  "trade_no": "5090058146920009728",
  "qrcode": "https://qr.alipay.com/..."
}
失败响应
{
  "code": -1,
  "msg": "签名校验未通过,请检查签名算法、参与签名的参数原文和支付对接密钥(请求编号:xxxxxxxxxxxxxxxx)"
}
提供请求编号可加快排查

签名失败时请保留响应中的请求编号,并向技术支持提供 PID、请求时间和脱敏后的参数名称列表。请勿发送支付对接密钥或完整回调 Token。

06

NOTIFICATION

支付回调

支付成功后,平台会向下单时的 notify_url 发送异步通知,并向 return_url 携带同步跳转参数。为兼容不同通道版本,接收端应同时读取 URL 查询参数和表单参数;只有异步通知可以作为可靠到账依据。

回调请求读取规则

PHP 可使用 array_replace($_GET, $_POST) 合并回调字段,同名字段以 POST 为准。无论参数来自 GET 还是 POST,都必须使用框架解析后的原始字段值验签,不要先做 HTML 转义、trim 或金额格式化。

参数类型说明
pidString商户 PID。
trade_noString平台支付订单号。
out_trade_noString你的商户订单号。
typeString支付分类。
nameString商品名称。
moneyString商户订单金额,固定两位小数,例如 1.00
trade_statusString只有精确等于 TRADE_SUCCESS 才表示成功。
paramString下单扩展参数;下单未传时可能不存在。
signString使用支付对接密钥按相同算法验签。
sign_typeString固定为 MD5
1
先验签

使用收到的原始参数验签,失败立即拒绝。

2
再核订单

核对 PID、订单号、订单金额与本地待支付记录。

3
幂等入账

trade_noout_trade_no 加唯一约束,重复通知不能重复发货。

4
最后应答

业务处理成功后返回纯文本小写 success,不要附加 HTML 或 JSON。

严禁只凭浏览器跳转发货

return_url 可能被用户关闭、重复访问或伪造。同步页只用于展示结果,必须以已验签的异步通知或主动查单结果更新订单。

PHP:回调入口的正确读取与验签顺序
<?php
$params = array_replace($_GET, $_POST); // POST 覆盖同名 GET
$clientSign = (string)($params['sign'] ?? '');

if ($clientSign === '' || !hash_equals(makeSign($params, getenv('DUOCAI_PAY_KEY')), $clientSign)) {
    http_response_code(400);
    exit('fail');
}
if (($params['trade_status'] ?? '') !== 'TRADE_SUCCESS') {
    http_response_code(400);
    exit('fail');
}

// 接下来必须在事务中:锁定本地订单,核对 pid/out_trade_no/money,
// 仅把“未支付”更新为“已支付”,重复通知直接返回 success,禁止重复发货。
// updateLocalOrderOnce($params);
exit('success');
07

ORDER QUERY

订单查询

POST / GEThttps://pay.1kexiu.xyz/api.php

查询接口使用 pid 与支付对接密钥 key 鉴权,并只返回该 PID 自己的订单。推荐服务端使用 POST 表单,避免密钥出现在 URL、浏览器历史和代理日志中;GET 仅为兼容旧客户端保留。

POST查询商户状态
act=query&pid=YOUR_PID&key=YOUR_PAY_KEY

成功时返回 code=1、开通状态、余额、用户名及套餐支持的支付分类;可用于服务器端连通性检查。

POST查询单个订单
act=order&pid=YOUR_PID&key=YOUR_PAY_KEY&out_trade_no=ORDER_NO

可传 out_trade_no(商户订单号)或 trade_no(平台订单号),只会查询当前 PID 的订单。

POST查询订单列表
act=orders&pid=YOUR_PID&key=YOUR_PAY_KEY&limit=20&page=1

limit 范围 1–50,page 从 1 开始。不要用高频轮询替代异步回调。

cURL:推荐的 POST 查单方式
curl --request POST 'https://pay.1kexiu.xyz/api.php' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'act=order' \
  --data-urlencode 'pid=YOUR_PID' \
  --data-urlencode 'key=YOUR_PAY_KEY' \
  --data-urlencode 'out_trade_no=ORDER_NO'

单笔订单成功响应示例

JSON
{
  "code": 1,
  "trade_no": "5090058146920009728",
  "out_trade_no": "ORDER_202608130001",
  "type": "alipay",
  "money": "0.01",
  "price": "0.01",
  "status": 1,
  "pay_time": "2026-08-26 12:00:00"
}
act=query 的兼容响应包含 key

这是为旧协议兼容保留的字段。查询接口只能由你的服务端调用,禁止把完整响应转发给浏览器、APP 或第三方日志平台。

status = 0未支付 / 等待支付
status = 1支付成功
08

TROUBLESHOOTING

错误处理与重试

不能只看 HTTP 状态码

接口的业务失败可能仍返回 HTTP 200。mapi.phpapi.php 必须解析 JSON 并判断 codesubmit.php 失败时可能返回带错误说明的 HTML 页面。

签名校验未通过最常见

确认使用支付对接密钥;按 ASCII 排序;空值、signsign_type 不参与;所有实际发送的非空参数都参与签名。重点检查回调 URL 中的 & 是否在签名前被错误转成 &amp;,或是否发生 trim、金额格式化及二次 URL 编解码。

商户 PID 或支付对接密钥错误

仅用于 api.php 查单鉴权。确认传的是商户中心“API 配置”中的 PID 和“对接密钥(KEY)”,不是登录密码、软件密钥或下单签名 sign

回调地址(return_url)不能为空

新版页面支付和 API 下单都需要传 return_url。它与 notify_url 是两个不同地址,且都应使用绝对 HTTPS URL。

当前商户无通道可用

检查套餐是否有效、所选 type 是否存在已启用通道、通道配置是否保存完整,以及通道限额/轮询配置。

商户余额不足无法发起支付

当前套餐存在费率且手续费余额不足。先在商户中心充值手续费余额,再重新发起。

订单号格式不正确 / 此订单已支付成功

out_trade_no 只使用字母、数字及 . _ - |;支付状态不确定时先查单,不要盲目更换订单号再次发货。

安全重试顺序
  1. 请求超时或响应无法解析时,保留原 out_trade_no
  2. 调用订单查询接口确认是否已建单或已支付。
  3. 只有确认未支付且业务允许时再重试;回调处理始终保持幂等。
09

AI ASSISTED INTEGRATION

复制提示词,让 AI 按真实规则接入

把下面整段提示词复制给 ChatGPT、Codex、Claude、Cursor 或其他编程助手。提示词已经写明接口、签名、回调、查单、测试和交付要求,可减少 AI 猜错参数或直接提交占位签名的问题。

OFFICIAL SERVER DEMO

先跑通固定签名,再接进你的项目

一包包含 PHP 8+、Node.js 18+、Python 3.9+ 三套无框架示例,以及下单、查单、回调验签模板和离线签名测试。

v1.0.014.5 KB无真实密钥不含第三方依赖
SHA-2562e133f7d2e80469a67830e7118b0d8651b3a76186d2ebffbf7e013a785adb9f8
下载完整 Demo ZIP 下载后先阅读 README.md
不要把真实密钥粘贴到聊天中

让 AI 使用 DUOCAI_PIDDUOCAI_PAY_KEY 环境变量。你只需在自己的服务器配置真实值,提示词和代码仓库中都不要出现明文密钥。

DuoCai码支付 · AI 通用接入提示词
你是一名资深支付接口集成工程师。请在我现有的项目中完成 DuoCai码支付接入,并以 https://pay.1kexiu.xyz/docs/api 为接口规则来源。先只读检查项目已有的订单、支付、回调、数据库和配置实现,优先复用现有结构,禁止重写无关模块、升级框架或修改第三方依赖。

【我的接入目标】
1. 接口域名:https://pay.1kexiu.xyz
2. 商户 PID:从环境变量 DUOCAI_PID 读取。
3. 支付对接密钥:从环境变量 DUOCAI_PAY_KEY 读取。
4. 需要接入的支付分类:alipay、wxpay;如果项目还需要 qqpay,再一并支持。
5. 优先使用服务端 POST /mapi.php 创建订单并获取支付地址;如果现有项目必须让浏览器直接跳转,则使用服务端生成签名后的 POST /submit.php 自动提交表单。
6. 不要要求我把真实 PID 或密钥粘贴到聊天中,不要把密钥写入前端、APP、日志、异常信息或代码仓库。

【必须严格实现的签名规则】
1. 使用 application/x-www-form-urlencoded 解析后的原始字段值。
2. 排除 sign、sign_type、a、c、m、s。
3. 排除值为 null 或空字符串的字段;数字 0 和字符串 0 必须参与签名。
4. 其余实际发送的字段按参数名升序排序。
5. 按 参数名=原始参数值 拼接,字段之间使用 & 连接。
6. 在完整参数串末尾直接追加 DUOCAI_PAY_KEY 的值,不要追加 &key=,然后计算 UTF-8 字节的 32 位小写 MD5。
7. 必须先使用原始值计算签名,再进行表单 URL 编码并发送。
8. 签名前禁止执行 htmlspecialchars、htmlentities、trim、大小写转换、金额格式重写、JSON 转义、URL 重组或二次 urlencode/urldecode。
9. notify_url 和 return_url 可以携带多个查询参数;其中的原始 & 必须参与签名,不能改成 &amp;。
10. 请求中的 money 按实际发送的原始字符串签名;回调中的 money 按平台实际返回值验签,通常为两位小数。

【创建订单】
使用 POST https://pay.1kexiu.xyz/mapi.php,Content-Type 为 application/x-www-form-urlencoded。至少发送:
pid、type、out_trade_no、notify_url、return_url、name、money、sign、sign_type=MD5。
param、clientip、device 等可选字段只要非空并实际发送,就必须参与签名。
return_url 在当前系统中为必填字段。
out_trade_no 必须唯一,只允许字母、数字和 . _ - |。
不要把 SERVER_GENERATED_SIGN 当作真实签名,它只是文档占位符。

接口业务失败可能仍返回 HTTP 200,所以必须解析 JSON 并判断 code。code=1 才表示下单成功。成功响应可能返回 payurl,也可能返回 qrcode;代码要兼容两者,优先使用实际非空字段,并保存平台 trade_no。不要只根据 HTTP 状态码判断成功。

如果使用 /submit.php,它返回 HTML 收银台页面,不是 JSON。签名必须仍在服务端生成,浏览器只能接收已经签好的自动提交表单,不能接触支付密钥。

【异步回调】
1. notify_url 接收端同时兼容 URL 查询参数和 POST 表单;PHP 可用 array_replace($_GET, $_POST),同名字段以 POST 为准,其他语言实现同等逻辑。
2. 使用收到的原始字段重新计算签名,并用安全比较函数核对 sign。
3. 验证 trade_status 必须等于 TRADE_SUCCESS。
4. 按 out_trade_no 查询本地订单,核对 pid、money、订单状态和平台 trade_no。
5. 使用数据库事务、行锁或唯一约束实现幂等:同一订单重复通知不能重复加款、发货或执行权益。
6. 业务处理成功后只返回纯文本 success;失败返回 fail 或非 2xx,不能误返回 success。
7. return_url 只用于浏览器展示,禁止仅凭同步跳转更新付款状态或发货。

【主动查单】
使用服务端 POST https://pay.1kexiu.xyz/api.php,表单参数使用 pid 和 key 鉴权,key 的值来自 DUOCAI_PAY_KEY,不使用下单 sign 代替 key。
单笔查单:act=order,加 out_trade_no 或 trade_no。
订单列表:act=orders,加 page 和 limit,limit 范围 1 至 50。
商户状态:act=query。
解析 JSON 并判断 code;单笔订单的 status=1 才表示支付成功。GET 查询仅为兼容旧客户端,不要在新代码中把密钥放进 URL。

【固定签名测试向量】
先为签名函数编写自动化测试,下面参数必须得到指定 MD5:
pay_key = test_pay_key_20260813
pid = M1234567890
type = alipay
out_trade_no = ORDER202608130001
notify_url = https://shop.example.com/pay/notify?channel=alipay&version=2
return_url = https://shop.example.com/pay/return?order=ORDER202608130001&source=pay
name = 测试订单
money = 1.00
expected_sign = beddd35092c3afea54c5218de0872502

测试还必须覆盖:空字符串、null、数字 0、money 分别为 1/1.0/1.00、中文商品名、空格、+、%、引号,以及 notify_url/return_url 含多个 &。同时验证签名后再做表单编码,确保实际发送字段与参与签名字段完全一致。

【实现与安全要求】
1. 先找到项目已有的订单模型、支付服务、回调路由和配置方式,做最小修改并保持现有代码风格。
2. PID 和密钥只从服务端环境变量或安全配置读取;日志不得记录密钥、完整签名原文或完整回调 Token。
3. 不关闭 TLS 证书验证,不使用浮点数直接比较金额;金额使用 decimal 或整数分,并按业务规则精确比较。
4. 请求超时或响应不确定时保留原 out_trade_no,先查单再决定是否重试,禁止生成新订单号后盲目重复下单。
5. 未经我明确确认,不进行真实付款、退款、发货或生产数据写入测试。可以先做固定向量、Mock 测试和无资金验证。
6. 如果现有项目规则与接口要求冲突,先指出具体文件和冲突原因,再给出保持兼容的最小修复,不要自行猜测。

【完成后请交付】
1. 说明修改了哪些文件、每个文件做了什么。
2. 给出需要配置的环境变量和部署步骤。
3. 给出签名、下单响应、回调幂等和主动查单的自动化测试结果。
4. 明确哪些内容已经实际验证、哪些因为没有真实付款而尚未验证。
5. 提供一个安全的联调检查清单;如果失败,输出脱敏后的参数名称、排序结果和请求编号,但绝不输出真实密钥。

现在请先检查我的项目结构和现有支付实现,然后直接完成最小范围接入。如果你不能直接读取或修改项目,就按我的技术栈输出可复制的完整文件,并明确每个文件的放置路径。
10

CODE EXAMPLES

可直接改造的服务端示例

示例均完成“过滤 → 排序 → 拼接 → MD5”。请把凭证放入环境变量,生产环境不要关闭 TLS 证书校验。

PHP 8+:签名并 API 下单
<?php
$apiBase = 'https://pay.1kexiu.xyz';
$payKey  = getenv('DUOCAI_PAY_KEY');

function makeSign(array $params, string $key): string {
    unset($params['sign'], $params['sign_type'],
          $params['a'], $params['c'], $params['m'], $params['s']);
    $params = array_filter($params, fn($v) => $v !== '' && $v !== null);
    ksort($params, SORT_STRING);
    $pairs = [];
    foreach ($params as $name => $value) {
        $pairs[] = $name . '=' . $value;
    }
    return md5(implode('&', $pairs) . $key);
}

$params = [
    'pid'          => getenv('DUOCAI_PID'),
    'type'         => 'alipay',
    'out_trade_no' => 'ORDER_' . date('YmdHis'),
    'notify_url'   => 'https://shop.example.com/pay/notify?channel=alipay&version=2',
    'return_url'   => 'https://shop.example.com/pay/return?order=ORDER_202608130001&source=pay',
    'name'         => '测试商品',
    'money'        => '0.01',
];
$params['sign'] = makeSign($params, $payKey);
$params['sign_type'] = 'MD5';

$ch = curl_init($apiBase . '/mapi.php');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    // 先用原始字段值签名,再编码发送;不要先对 URL 做 htmlspecialchars。
    CURLOPT_POSTFIELDS => http_build_query($params),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
]);
$result = json_decode(curl_exec($ch), true, 512, JSON_THROW_ON_ERROR);
curl_close($ch);
if (($result['code'] ?? -1) !== 1) {
    throw new RuntimeException($result['msg'] ?? '下单失败');
}
// 优先使用实际存在的字段:payurl 或 qrcode
$paymentValue = $result['payurl'] ?? $result['qrcode'] ?? null;

回调验签最小逻辑

伪代码(适用于任意语言)
params = merge_query_and_form_params(request)
if make_sign(params, PAY_KEY) != params.sign:
    return "fail"
if params.trade_status != "TRADE_SUCCESS":
    return "fail"
order = find_local_order(params.out_trade_no)
if order is null or order.pid != params.pid or order.money != params.money:
    return "fail"
mark_paid_once(order, params.trade_no)  // 必须幂等
return "success"                       // 纯文本
11

GO LIVE

上线前检查清单

仍有对接问题?带上订单号和脱敏后的请求参数,开发群里更容易快速定位。
加入 QQ 群 100687286