接入指南

本文面向业务系统开发者,说明如何将 EasyIT Pay 集成到现有项目中。

整体流程

┌─────────────┐    ①创建订单     ┌─────────────┐    ②跳转     ┌─────────────┐
│  业务系统    │ ──────────────▶ │  支付平台    │ ──────────▶ │   收银台     │
│             │ ◀────────────── │             │ ◀────────── │             │
└─────────────┘  ④异步通知       └─────────────┘  ③用户支付   └─────────────┘
       ▲
       └── ⑤ return_url 同步回跳

第一步:获取凭证

  1. 登录 管理后台
  2. 进入 接入应用创建应用
  3. 记录返回的 app_idapp_secret(密钥仅展示一次,请妥善保存)

app_secret 用于 API 签名,切勿暴露在前端代码或公开仓库中。

第二步:配置回调地址

创建订单时需传入两个 URL:

字段用途要求
notify_url支付成功后平台服务端 POST 回调必须公网可访问(开发可用内网穿透)
return_url支付完成后用户浏览器跳转可为业务前端页面

业务系统需在 notify_url 接口中:

  • 验证签名(平台回调携带 HMAC 签名)
  • 幂等处理(同一订单可能重复通知)
  • 返回 success 字符串表示接收成功

第三步:创建订单

调用 POST /api/v1/orders,详见 Open API 文档

请求成功后返回:

{
  "code": 0,
  "data": {
    "order_no": "P202505300001",
    "pay_url": "http://127.0.0.1:8010/pay/abc123token",
    "expire_at": "2025-05-30T12:30:00Z"
  }
}

将用户浏览器重定向至 pay_url 即可进入收银台。

第四步:处理支付结果

异步通知(推荐)

平台向 notify_url POST JSON,包含订单号、金额、支付状态等。业务系统更新本地订单状态后返回 success

同步回跳

用户支付完成后跳转 return_url,可携带订单号等参数。注意:同步回跳不能作为最终支付凭证,务必以异步通知为准。

主动查询

若长时间未收到回调,可调用 GET /api/v1/orders/{out_trade_no} 主动查询订单状态。

签名规则

所有 Open API 请求需携带 HMAC-SHA256 签名:

  1. 取除 sign 外所有字段
  2. 按 key 字母序排列,拼接为 key1=value1&key2=value2&...
  3. 使用 app_secret 作为密钥,计算 HMAC-SHA256 十六进制字符串
  4. 将结果填入 sign 字段

空值字段不参与签名;timestamp 与服务器时间差不超过 5 分钟。

注意事项

  • out_trade_no 在同一 app_id 下必须唯一
  • 金额单位为 (整数),如 1 元 = 100
  • 订单默认 30 分钟过期,过期后需重新创建
  • 生产环境请关闭演示模式,配置真实商户密钥

示例代码思路(伪代码)

import hmac, hashlib, time, uuid, requests

def sign(params: dict, secret: str) -> str:
    items = sorted((k, v) for k, v in params.items() if k != "sign" and v is not None)
    raw = "&".join(f"{k}={v}" for k, v in items)
    return hmac.new(secret.encode(), raw.encode(), hashlib.sha256).hexdigest()

payload = {
    "app_id": "app_xxx",
    "out_trade_no": "ORDER001",
    "amount": 100,
    "subject": "测试商品",
    "notify_url": "https://biz.example.com/pay/notify",
    "return_url": "https://biz.example.com/pay/return",
    "timestamp": int(time.time()),
    "nonce": uuid.uuid4().hex,
}
payload["sign"] = sign(payload, APP_SECRET)

resp = requests.post(f"{PAY_BASE}/api/v1/orders", json=payload)
pay_url = resp.json()["data"]["pay_url"]
# redirect user to pay_url

下一步