接入概述
已经对接过易支付的系统,改一下地址和密钥即可使用
泡泡支付完整兼容易支付 V1 协议。如果你的系统(发卡网、AI 站、各类商城插件)已经支持易支付,不需要改代码,只要把后台的网关地址、商户 ID、商户密钥换成泡泡支付提供的即可。
网关地址
| 用途 | 地址 | 方式 |
|---|---|---|
| API 下单(后端发起,返回支付链接) | {网关域名}/mapi.php | POST |
| 页面下单(浏览器直接跳转) | {网关域名}/submit.php | GET / POST |
| 综合接口(查单、退款、结算等) | {网关域名}/api.php | GET / POST |
部分系统只要求填一个「网关地址」,此时填到域名即可,系统会自行拼接 /mapi.php 等路径。
商户 ID 与密钥
联系官方客服开通接入应用,网关域名、pid 与 key 由客服直接提供给你:
| 易支付字段 | 对应泡泡支付 | 说明 |
|---|---|---|
pid | 接入应用的「商户 ID」 | 6 位以上纯数字 |
key | 接入应用的「商户密钥」 | 32 位字符,仅用于签名,切勿泄露 |
若怀疑密钥泄露,可联系官方客服重置。重置后必须同步更新你系统里的配置,否则签名会全部失败。
接口 IP 白名单
/mapi.php 与 /api.php 是服务器对服务器调用,受 IP 白名单限制。需要把你服务器的公网出口 IP 提供给官方客服配置到白名单中,否则会返回「非法请求,请添加接口IP白名单」。
/submit.php 由用户浏览器直接访问,来源是用户 IP,因此不校验白名单,仅靠签名保证请求真实性。
签名算法
对接期绝大多数问题都是签名对不上。本节给出一组可直接比对的完整示例:如果你用相同入参算不出相同的 sign,对照下面四步逐步排查即可定位。
四步规则
- 筛选:剔除
sign、sign_type,以及值为空的参数 - 排序:按参数名 ASCII 升序(a→z)排列
- 拼接:拼成
k1=v1&k2=v2,值不做 URL 编码 - 签名:末尾直接追加商户密钥(没有
&key=分隔),MD5 取 32 位小写
完整示例
按顺序切换下面的标签页,逐步比对。注意 param 为空,不参与签名;第 ③ 步密钥直接拼在末尾,中间没有任何分隔符。
pid = 100001
type = alipay
out_trade_no = MCH20260728001
notify_url = https://shop.com/notify
return_url = https://shop.com/return
name = VIP会员
money = 1.00
clientip = 1.2.3.4
param = ← 空值,剔除
key(密钥) = a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6最终请求里再带上 sign=77c46b1a2cb7063f4d01003379863f5e 和 sign_type=MD5 两个参数即可。
容易踩的三个点
| 现象 | 原因 |
|---|---|
| 本地算的 sign 与平台不一致 | 最常见是对参数值做了 URL 编码。中文、://、& 都要用原文参与签名,编码只发生在实际发送 HTTP 请求时 |
| 加上某个空参数就签不过 | 空值必须剔除。传了 param= 却把它算进签名串,就会不一致 |
| 偶发验签失败,多数订单正常 | 检查商品名是否含尖括号或首尾空格,确保发送的值与参与签名的值完全一致 |
API 下单
后端发起,返回支付链接或二维码内容,由你自己决定怎么展示给用户。请求体为 application/x-www-form-urlencoded,仅支持 POST,受 IP 白名单限制。
请求参数
| 参数名 | 必填 | 说明 |
|---|---|---|
pid | 是 | 商户 ID |
type | 是 | 支付方式:alipay / wxpay / qqpay |
out_trade_no | 是 | 商户订单号,同一应用内不可重复(最长 64 字符) |
notify_url | 是 | 异步通知地址,发货请以此为准 |
name | 是 | 商品名称 |
money | 是 | 金额(元),最多 2 位小数,最小 0.01 |
clientip | 是 | 用户 IP |
return_url | 否 | 支付后浏览器跳转地址 |
device | 否 | 设备类型,不传自动识别 |
param | 否 | 业务扩展参数,通知时原样返回 |
sign | 是 | 签名 |
sign_type | 是 | 固定 MD5 |
响应参数
| 参数名 | 说明 |
|---|---|
code | 1 为成功,-1 为失败 |
msg | 失败原因,成功时为空串 |
trade_no | 平台订单号 |
out_trade_no | 商户订单号 |
money | 订单金额 |
payurl | 支付跳转链接(http/https) |
qrcode | 二维码内容(weixin://、alipays:// 等) |
urlscheme | 小程序跳转链接 |
payurl、qrcode、urlscheme三者只返回其中一个,取决于实际出码的通道类型。你的代码要三个都做兼容判断。
{
"code": 1,
"msg": "",
"trade_no": "PN20260728120000123",
"out_trade_no": "MCH20260728001",
"money": "1.00",
"payurl": "https://pay.example.com/xxxx"
}页面下单
把用户浏览器直接引导到本地址(表单 POST 或拼 query 串 GET 都可以),平台下单后自动跳转到支付页面,适合不想自己处理支付页展示的场景。本接口不校验 IP 白名单(访问者是终端用户),仅靠签名保证真实性。
请求参数
| 参数名 | 必填 | 说明 |
|---|---|---|
pid | 是 | 商户 ID |
out_trade_no | 是 | 商户订单号 |
notify_url | 是 | 异步通知地址 |
return_url | 是 | 支付后跳转地址 |
name | 是 | 商品名称 |
money | 是 | 金额(元) |
type | 否 | 支付方式,不传则跳转平台收银台由用户自选 |
param | 否 | 业务扩展参数 |
sign | 是 | 签名 |
sign_type | 是 | 固定 MD5 |
响应是一个自动跳转的 HTML 页面。若参数或签名有误,返回的是可读的错误提示页,页面上会写明具体原因,可据此排查。
异步通知
支付成功后,平台以 GET 方式请求你的 notify_url,参数拼在 query 上。发货必须以异步通知为准,不要依赖同步跳转。
通知参数
| 参数名 | 说明 |
|---|---|
pid | 商户 ID(与你下单时用的一致) |
trade_no | 平台订单号 |
out_trade_no | 商户订单号 |
type | 支付方式,回传你下单时传的原值 |
name | 商品名称 |
money | 订单金额 |
trade_status | 只有 TRADE_SUCCESS 表示成功 |
param | 下单时传的业务扩展参数(下单未传则不出现) |
sign | 签名,请务必验签 |
sign_type | MD5 |
你需要返回什么
处理成功后,页面只输出 success 七个字符(ok 也可接受),不要包含 HTML 标签或其他内容。
若未收到 success,平台会自动重试,间隔逐次递增。因此你的处理逻辑必须做幂等:同一 out_trade_no 收到多次通知只能发货一次。
GET https://shop.com/notify?money=1.00&name=VIP%E4%BC%9A%E5%91%98&out_trade_no=MCH20260728001
&pid=100001&sign=xxxxxxxx&sign_type=MD5&trade_no=PN20260728120000123&trade_status=TRADE_SUCCESS验签时用的是 URL 解码后的参数值。多数框架(PHP 的 $_GET、Java 的 getParameter)已自动解码,直接取用即可。
补发通知
若你的服务当时不可用错过了通知,可调用综合接口 /api.php?act=notify 主动要求平台重发,无需联系客服。
同步跳转
用户支付完成后跳回你的 return_url,参数与异步通知一致,可用于展示「支付成功」页面。submit.php 下单时该参数必填,mapi.php 下单时可选。
同步跳转不保证一定发生,且不可作为发货依据。是否跳回、以及跳回时带哪些参数,取决于实际出码的上游通道,部分通道支付完成后用户会停留在通道页面,这与易支付原版的情况一致。你的成功页应当再查一次订单状态(act=order),而不是直接相信跳转本身。
综合接口
查单、退款、结算等操作都走这个地址,用 act 区分。本系列接口不用签名,而是直接传 key(商户密钥)校验,这是易支付协议的约定。
因为 key 会出现在 URL 上,请仅在服务端调用,不要放到前端代码里。本接口受 IP 白名单限制。
公共参数
| 参数名 | 必填 | 说明 |
|---|---|---|
act | 是 | 操作类型,见下文 |
pid | 是 | 商户 ID |
key | 是 | 商户密钥(明文) |
act=order 查单
额外参数:trade_no(平台单号)或 out_trade_no(商户单号),二选一,同时传则 trade_no 优先。
| 返回字段 | 说明 |
|---|---|
status | 1 = 支付成功,0 = 其他状态(未付、失败、已关闭) |
trade_no / out_trade_no | 平台单号 / 商户单号 |
api_trade_no | 上游通道订单号 |
type | 支付方式(你下单时传的原值) |
money | 订单金额 |
name | 商品名称 |
addtime / endtime | 创建时间 / 支付完成时间 |
param | 业务扩展参数 |
GET /api.php?act=order&pid=100001&key=你的密钥&out_trade_no=MCH20260728001act=orders 批量查单
额外参数:limit(每页条数,最大 50,默认 20)、page(页码,从 1 开始)。返回 data 数组,每项字段与 act=order 一致,按创建时间倒序。
act=query 查账户信息
| 返回字段 | 说明 |
|---|---|
money | 账户余额 |
active | 1 = 账户正常,0 = 已停用 |
order_today / order_lastday | 今日 / 昨日订单数 |
key | 原样回显请求时传入的商户密钥(与 V1 一致),便于部分系统的「测试连接」比对配置 |
type / account / username | 协议中为结算方式与结算账户信息。泡泡支付结算由官方统一处理,不通过接口暴露,返回空串占位 |
orders | 协议中为历史累计订单数,泡泡支付未维护该口径,返回 0 占位,需要统计请用 act=orders |
act=settle 查结算记录
返回 data 数组(最近 50 条),字段:id、money(结算金额)、addtime、remark。结算在账户维度进行,同账户下多个应用共享结算记录。
act=refund 申请退款(POST)
| 参数名 | 必填 | 说明 |
|---|---|---|
trade_no | 二选一 | 平台订单号 |
out_trade_no | 二选一 | 商户订单号 |
money | 是 | 退款金额,少数通道需与原订单金额一致 |
trade_no 与 out_trade_no 不能同时为空,都传则以 trade_no 为准。
本接口 code=0 表示成功,与其他所有 act 的 code=1 相反。这是易支付 V1 协议的定义,泡泡支付保持一致以兼容既有客户端,请勿按 code=1 判断。
act=notify 补发通知(扩展)
额外参数:trade_no 或 out_trade_no(二选一)。仅支付成功的订单可补发。返回 code=1 表示补发任务已提交,通知为异步发送,不代表你已成功接收。该 act 不属于 V1 标准接口,是泡泡支付的扩展,用于商户自助补发错过的通知。
常见系统配置对照
各家系统的字段叫法不同,下表把常见系统后台的配置项对应到泡泡支付的值,照着填完就能跑,不需要读上面的协议细节。开始前先联系官方客服开通接入应用,拿到 pid 和 key。
通用对应关系
| 对方系统里的叫法 | 填什么 |
|---|---|
| 支付接口地址 / 网关地址 / API 地址 / 接口 URL | 客服提供的网关域名,如 https://网关域名 |
| 商户 ID / 商户号 / PID / 合作者身份 | 接入应用的商户 ID(pid) |
| 商户密钥 / 通信密钥 / KEY / Token | 接入应用的商户密钥(key) |
| 签名方式 / 加密方式 | MD5 |
| 支付方式编码 / 通道编码 | alipay(支付宝)、wxpay(微信) |
| 接口版本 / 协议版本 | 选「易支付」或「彩虹易支付」;若区分版本选 V1 |
发卡网系统
| 系统 | 配置位置 | 要点 |
|---|---|---|
| 异次元发卡 | 后台 → 支付接口 → 新增,类型选「彩虹易支付 / 易支付」 | 「接口地址」填到域名即可,程序自动拼 /submit.php;商户 ID 填 pid,密钥填 key |
| 独角数卡 | 管理后台 → 支付配置 → 添加支付方式,选 Epay / 易支付 | 需分别为支付宝和微信各加一条,两条的 pid / key 相同,只有「支付类型」分别填 alipay / wxpay |
| 彩虹发卡 / 各类彩虹二开 | 后台 → 支付设置 → 易支付 | 原生同源协议,通常只需替换网关地址、PID、KEY 三项 |
AI 站 / API 中转站
| 系统 | 配置位置 | 要点 |
|---|---|---|
| One-API / New-API / 各类二开 | 系统设置 → 支付设置(或支付宝 / 易支付相关配置项) | 「易支付接口地址」填网关域名,「易支付商户ID」填 pid,「易支付商户密钥」填 key。部分版本要求地址以 / 结尾,按其占位提示填 |
| 自建站 / 其他商城插件 | 凡是支持「易支付」的插件 | 按上面「通用对应关系」逐项填即可 |
别忘了 IP 白名单:把你服务器的公网出口 IP 提供给官方客服配置进应用中,否则 /mapi.php 和 /api.php 会被拒绝。纯用 /submit.php 跳转的系统不受此限制。
代码示例
下面是签名、下单、验签三段核心代码。把 GATEWAY、PID、KEY 换成你自己的即可运行。
<?php
const GATEWAY = 'https://pay.example.com'; // 网关地址,开户后由官方客服提供
const PID = '100001';
const KEY = '你的商户密钥';
/** 生成签名:剔除空值与 sign/sign_type,按键名排序,拼接后追加密钥取 MD5 */
function epaySign(array $params, string $key): string {
unset($params['sign'], $params['sign_type']);
$params = array_filter($params, fn($v) => $v !== '' && $v !== null);
ksort($params);
$parts = [];
foreach ($params as $k => $v) {
$parts[] = "$k=$v"; // 注意:值不做 urlencode
}
return md5(implode('&', $parts) . $key);
}
/** 下单,返回支付地址 */
function epayCreate(array $biz): array {
$params = array_merge($biz, ['pid' => PID]);
$params['sign'] = epaySign($params, KEY);
$params['sign_type'] = 'MD5';
$ch = curl_init(GATEWAY . '/mapi.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$resp = curl_exec($ch);
curl_close($ch);
$data = json_decode($resp, true);
if (!$data || ($data['code'] ?? -1) != 1) {
throw new Exception('下单失败:' . ($data['msg'] ?? $resp));
}
// payurl / qrcode / urlscheme 三者只返回其一,都要兼容
$data['pay_target'] = $data['payurl'] ?? $data['qrcode'] ?? $data['urlscheme'] ?? '';
return $data;
}
// ---------- 下单 ----------
$order = epayCreate([
'type' => 'alipay',
'out_trade_no' => 'MCH' . date('YmdHis'),
'notify_url' => 'https://shop.com/notify.php',
'return_url' => 'https://shop.com/return.php',
'name' => 'VIP会员',
'money' => '1.00',
'clientip' => $_SERVER['REMOTE_ADDR'],
]);
header('Location: ' . $order['pay_target']);
// ---------- 接收异步通知(notify.php) ----------
$params = $_GET; // 框架已自动 urldecode
if (epaySign($params, KEY) !== ($params['sign'] ?? '')) {
exit('sign error'); // 验签失败,不可发货
}
if (($params['trade_status'] ?? '') !== 'TRADE_SUCCESS') {
exit('success'); // 非成功状态,应答避免重试
}
// 幂等:同一订单号可能收到多次通知,必须保证只发货一次
if (!alreadyShipped($params['out_trade_no'])) {
ship($params['out_trade_no'], $params['money']);
}
exit('success'); // 只输出 success,不要带 HTML排错指引
| 返回信息 | 原因与处理 |
|---|---|
| 验签失败 | 最常见是对参数值做了 URL 编码后再签名,中文、:// 要用原文参与签名。其次检查是否把空值参数算进了签名串。请对照「签名算法」一节的完整示例逐步比对 |
| 非法请求,请添加接口IP白名单 | 把你服务器的公网出口 IP 提供给官方客服配置到白名单中。注意是出口 IP,不是内网 IP,也不是用户 IP |
| 商户不存在,请刷新 | pid 填错,或填的是别人的 pid,请核对客服提供的 pid |
| 接入应用已停用 | 联系官方客服把该应用状态改回「启用」 |
| 接入应用未配置支付方式 xxx 对应的产品 | 该应用没有为这个支付方式配置产品,请联系官方客服配置 |
| 商户订单号重复 | 同一应用内 out_trade_no 不可重复。若是重试导致,先用 act=order 查原单状态,不要换号重下 |
| 参数 money 格式错误 / 不能小于 0.01 / 最多保留 2 位小数 | 按提示修正金额,注意单位是元不是分 |
| 出码失败,暂无任何匹配支付链接可用 | 当前金额下没有可用通道。可换个金额再试,或联系官方客服确认通道状态与金额区间 |
| 订单不存在 | 单号填错,或该订单属于同账户下的另一个应用。查单时请用下单时那个应用的 pid / key |
| 收不到异步通知 | 确认 notify_url 是公网可访问的 http/https 地址、无需登录,且返回内容只有 success。确认无误后用 act=notify 补发 |
| 支付完成后没跳回网站 | 同步跳转取决于上游通道是否支持,部分通道不会跳回。这属于正常情况,请以异步通知为发货依据 |
上线前自查清单
- 已请官方客服为要用的支付方式各配置了一个产品
- 已把服务器公网出口 IP 加入白名单
- 签名串里没有 URL 编码、没有空值参数、末尾直接拼了密钥
- 下单响应对
payurl/qrcode/urlscheme三个字段都做了兼容 - 异步通知做了验签,且返回内容只有
success - 发货逻辑做了幂等,同一订单号重复通知只发一次
- 发货依据是异步通知,而不是同步跳转
获取商户 ID 与密钥
联系官方客服开通接入应用,网关地址、pid 与 key 由客服直接提供,专人协助联调。
联系官方客服