易支付对接指南
服务根地址:https://pay.strcpy.cn。当前只支持支付宝(alipay)。
本页与 AI 对接 Skill 均无需登录。商户 PID、商户 KEY 从管理员提供的网站接入信息中获取,每个网站使用独立凭据。商户 KEY 用于易支付签名,与支付宝应用私钥不同。
1. 配置接入网站
管理员在「接入网站」创建网站,选择收款应用,登记通知与返回地址。接入方填写:
| 配置 | 填写内容 |
|---|---|
| 支付地址 / API 地址 | https://pay.strcpy.cn,填写根地址,不追加 submit.php |
| 商户 PID | 该网站的 PID |
| 商户 KEY / PKey | 该网站的 KEY,保存在接入网站服务端 |
| 支付方式 | alipay |
| 通知地址 | 接入网站接收付款结果的完整 HTTP / HTTPS 地址 |
| 返回地址 | 用户付款后返回接入网站的完整 HTTP / HTTPS 地址 |
通知与返回地址登记时不带查询参数。实际请求可带查询参数,但协议、域名、端口、路径必须与登记值一致;路径末尾斜杠也要一致。通知必须公网可达,网关不跟随通知重定向,不向本机、内网及保留地址发送通知。
NewAPI
在 NewAPI 的易支付设置中填写以上根地址、PID、KEY,并启用支付宝。后台网站类型选择 NewAPI。
常用通知路径:/api/user/epay/notify、/api/subscription/epay/notify;订阅返回路径:/api/subscription/epay/return。充值返回路径因版本而异,例如 /console/log 或 /usage-logs。以实际版本下单请求里的完整地址为准,在支付后台登记;不要照搬其他站点的域名。
Sub2API
支付服务商选择 EasyPay,API 地址填写根地址,PID 和 PKey 填写网站凭据,支付方式选择 alipay,通道 ID 留空。本后台网站类型选择「通用易支付」。常用通知路径为 /api/v1/payment/webhook/easypay,返回路径为 /payment/result。
Sub2API 返回地址中的 order_id、out_trade_no、resume_token、status 查询参数在签名时原样保留。返回链接带有 status=success 不代表网关已确认付款,接入方仍需验签并查单或处理异步通知。
2. 接口与请求格式
| 接口 | 方法 | 行为 |
|---|---|---|
/submit.php |
GET / POST | 成功后以 HTTP 303 跳转至收银台 |
/mapi.php |
GET / POST | 成功返回 JSON,包含收银台链接 |
/api.php |
GET / POST | 使用 PID / KEY 查询订单 |
三个接口同时支持 /xpay/epay/ 前缀,例如 /xpay/epay/submit.php。POST 下单使用 Content-Type: application/x-www-form-urlencoded;不接受 JSON 下单。POST 参数放在请求体中,不混入 URL 查询参数。相同一级参数不得重复。
下单参数
| 字段 | 必填 | 含义与限制 |
|---|---|---|
pid |
是 | 网站商户 PID |
type |
是 | 固定为 alipay |
out_trade_no |
是 | 网站订单号,1–64 个英文字母、数字、下划线或短横线;同一网站唯一 |
name |
是 | 商品名称,UTF-8,最长 127 字节;原样传给支付宝 |
money |
是 | 元,十进制字符串,例如 10.06;最低 0.01,最多两位小数,且不超过网站单笔限额 |
notify_url |
是 | 已登记的异步通知地址 |
return_url |
是 | 已登记的付款返回地址 |
sign |
是 | 小写 MD5 签名,32 位十六进制 |
sign_type |
建议 | MD5;省略时也按 MD5 校验 |
device |
否 | pc 或 mobile,选择支付页面;也会参考浏览器 User-Agent 与应用可用产品 |
param |
否 | 透传字符串,最长 1024 字节;通知中原样返回 |
expiry_minutes |
否 | 本次订单有效期,1–21600 分钟的整数;不传时使用网站配置,默认 30 分钟 |
金额不要使用浮点数计算后再直接拼接。有效期截止时间按分钟向上取整,可能额外增加不足 60 秒。同一网站订单号重复提交返回 HTTP 409;发生超时先查原订单,不要直接生成另一笔订单。
3. MD5 签名与字段扩展
- 取表单解码一次后的所有一级字段,排除一级
sign、sign_type及值为空字符串的字段。 - 按字段名升序排列,拼接为
key=value&key=value,字段名大小写保留。 - 在拼接字符串末尾直接追加商户 KEY,不加
&key=。 - 对 UTF-8 字节计算 MD5,输出小写十六进制。
- 将签名加入参数后,再用标准表单编码生成请求体或查询字符串。
一级新增字段自动参与签名。URL、JSON 或 N 层嵌套数据作为一个完整字符串参与签名,不递归展开,不重新排序,也不再次解码。不要只签固定的几个字段;验签也必须包含收到的所有非空一级字段。
V1 对原始值使用 & 拼接,存在边界歧义。网关会拒绝值中 &字段名= 与同名保留字段取值冲突的请求。保留字段为 pid、type、money、out_trade_no、trade_no、trade_status、name、param、notify_url、return_url、expiry_minutes、sign、sign_type(边界检查不区分大小写)。普通 R&D、uid=5&plan=pro、非保留字段或重复值相同的合法参数可以使用。Sub2API 返回地址重复相同的 out_trade_no 可以通过。
回跳参数也不能与网关支付字段冲突。对于有歧义的业务数据,优先改用结构化 JSON 放入 param,或调整字段名;若必须对内层值编码,接入方需约定同一编码方式,不能对整个请求反复编码。
Python 下单示例
以下示例只生成请求体,不创建订单。将环境变量设为该网站实际配置后,将输出通过服务端 POST 发给 /mapi.php。PAY_RETURN_URL 可带接入网站需要的查询参数。
import hashlib
import os
from urllib.parse import urlencode
def epay_sign(fields, key):
pairs = [f"{k}={fields[k]}" for k in sorted(fields)
if k not in ("sign", "sign_type") and fields[k] != ""]
return hashlib.md5(("&".join(pairs) + key).encode("utf-8")).hexdigest()
fields = {
"pid": os.environ["PAY_PID"],
"type": "alipay",
"out_trade_no": os.environ["PAY_ORDER_NO"],
"name": "API 额度充值",
"money": "10.06",
"notify_url": os.environ["PAY_NOTIFY_URL"],
"return_url": os.environ["PAY_RETURN_URL"],
"param": '{"user_id":"42","plan":"pro"}',
"sign_type": "MD5",
}
fields["sign"] = epay_sign(fields, os.environ["PAY_KEY"])
print(urlencode(fields))
下单响应
/mapi.php 成功:
{"code":1,"msg":"success","trade_no":"CPexample","payurl":"https://pay.strcpy.cn/checkout/CPexample","money":"10.06"}
跳转用户到 payurl 完成付款。trade_no 是网关支付订单号,并非支付宝交易号。获得链接仅代表网关创建了待支付订单。
下单失败返回非 2xx HTTP 状态,响应体为文本。常见情况:400 参数、金额或回调地址错误;401 PID 或签名无效;409 订单重复或收款应用不可用;415 下单 POST 使用了错误 Content-Type。接入方先判断 HTTP 状态,再解析成功 JSON。
4. 异步通知与付款后返回
网关确认付款后,POST 表单到订单原始 notify_url,包含 pid、trade_no、out_trade_no、type、name、money、trade_status=TRADE_SUCCESS、sign_type=MD5、sign;非空 param 也包含在内。
接入网站按以下顺序处理:
- 拒绝重复一级参数,按本站 KEY 验证全部一级字段签名。
- 验证 PID、网站订单号、金额、支付方式和
TRADE_SUCCESS;金额按整数分比较。 - 在数据库事务内将订单标记为已支付并完成余额或订阅更新。以订单号做唯一约束,重复通知不重复入账。
- 事务成功提交后返回 HTTP 200,响应体为纯文本
success。已处理的合法重复通知也返回success。
通知失败会自动重试,间隔逐步增加;管理员也可手动重试。不要在写入失败时返回 success。
用户回跳为 GET,网关会将付款参数与原 return_url 查询参数合并并重新签名。验签必须包含所有合并后的非空一级字段。浏览器跳转本身不能证明付款,也不能仅靠 status=success、前端状态或收银台链接给用户入账。
付款状态与通知状态独立:已付款但通知失败仍是已付款。异步通知只发送付款结果,不提供退款扣回事件;退款需人工核对,业务系统自行处理退款后的余额和权益。
5. 订单查询
服务端 POST 到 https://pay.strcpy.cn/api.php,使用表单字段:
| 字段 | 含义 |
|---|---|
act |
固定 order |
pid |
网站 PID |
key |
网站 KEY;该接口直接校验凭据,不使用下单 MD5 签名 |
out_trade_no |
网站订单号;与 trade_no 至少传一个 |
trade_no |
网关支付订单号,通常以 CP 开头;两者都传时必须对应同一订单 |
成功返回 code=1、msg、pid、trade_no、out_trade_no、name、money、type、status、trade_status。只查询当前 PID 的订单。此接口返回网关已记录的付款状态,不实时调用支付宝。
status |
trade_status |
含义 |
|---|---|---|
0 |
WAIT_BUYER_PAY |
尚未确认付款 |
1 |
TRADE_SUCCESS |
已确认付款,与网站通知是否成功无关 |
0 |
TRADE_CLOSED |
已关闭或已过期 |
查单业务错误使用 HTTP 200、code=-1、msg。因此 HTTP 200 不等于业务成功。退款待核对订单也返回 code=-1(订单存在退款,请人工核对),不能当作可再次发货的已支付订单。没有退款、提现或修改订单接口。
6. 联调与常见问题
- 在管理员 Playground 模拟下单,核对请求参数、签名、响应、收银台和通知结果。首次真实付款需接入方按其测试安排完成。
- “易支付签名无效”:检查 PID / KEY 是否属于同一网站,是否签了全部非空一级字段,是否在签名后才进行表单编码。
- “通知或返回地址未在网站配置中登记”:对比实际协议、域名、端口、路径,去掉查询参数后与后台登记值逐项核对。
- 已付款但网站未入账:查看独立的通知状态,检查接入网站验签、事务及纯文本
success响应,再重试通知。 - 请求超时或订单重复:用原
out_trade_no查单,不重新发起另一笔充值。 - “参数边界”错误:检查字段值中的
&保留字段=,不要更改已经签名的值,参照第 3 节调整内层数据。
本页描述当前服务实现。接入资料中的网站凭据、账号权限及支付宝应用资料仍由管理员管理,公开文档不包含它们。