PAYATHON 2026

如何获取 Easy Pay2 API 并集成 payment gateway?

支付小周

结论

仅凭“Easy Pay2”这个名称,无法确认具体的支付服务商、API 地址或接口参数,也无法编写可用于生产环境的集成代码。接入支付网关前,商户需要向 Easy Pay2 的运营方、收单机构或代理商申请账号,并取得官方技术文档、测试环境凭证和签名规则,不能靠猜测接口完成接入。

如果找不到公开资料,先确认产品的完整名称、官方网站和合同主体。“Easy Pay2”可能是内部产品名、地区性支付服务、旧版系统,也可能是其他品牌的非正式写法。在服务商身份得到确认前,不要向未知地址发送订单、银行卡或用户资料。

接入前需要向服务商索取什么

联系 Easy Pay2 的商务或技术支持时,至少需要索取:

  • 商户后台地址和技术支持联系方式
  • API 文档或 Hosted Payment Page 接入文档
  • Sandbox 测试环境及测试账号
  • merchant_id、API Key、Client Secret 或证书
  • 创建支付、查询订单和退款接口
  • 支付完成后的浏览器返回规则
  • Webhook/Callback 异步通知规则
  • 请求签名与回调验签算法
  • 金额单位、币种格式和订单号限制
  • IP 白名单及 TLS 版本要求
  • 错误码、重试机制和接口限流规则
  • 上线审核流程及生产环境地址
  • PCI DSS、隐私保护和数据存储要求

可以直接向服务商询问:

请提供 Easy Pay2 支付网关的官方 API 文档、Sandbox 环境、商户凭证申请流程、签名与验签规范,以及支付、查询、退款和 Webhook 接口说明。另请确认产品的正式名称、官方网站和生产环境域名。

如果对方只能提供后台账号,却拿不出任何接口文档,需要继续确认该产品是否支持网站 API 集成。有些支付产品只提供付款链接、二维码、POS 或人工对账,不开放 API。

推荐的集成流程

1. 确认支付模式

支付网关通常有两种接入方式:

  • 托管收银台:网站创建支付订单后,把用户重定向到服务商的支付页面。这种方式接入成本较低,也能减少网站直接接触敏感支付数据的风险。
  • 服务端 API:网站后端直接调用网关接口,前端通过网关提供的组件完成支付。这种方式有更多控制能力,但安全和合规要求通常也更高。

除非 Easy Pay2 明确提供并授权直连支付 API,否则应优先使用托管收银台。不要自行采集或保存银行卡号、CVV、支付密码等敏感信息。

2. 在服务端创建本地订单

用户点击支付按钮后,应先在自己的数据库中创建订单,并保存以下信息:

  • 本地订单号
  • 应付金额和币种
  • 初始状态,例如 PENDING
  • 用户标识
  • 创建时间
  • 支付网关返回的交易号

金额应以最小货币单位的整数保存。例如,人民币 10.99 元可保存为 1099 分,避免浮点数精度问题。

3. 由后端调用支付网关

下面是一个通用的 Node.js 结构示例。代码中的字段名称、API 地址和签名方式都是占位设计,必须按照 Easy Pay2 官方文档替换,不能直接用于生产环境。

import crypto from "node:crypto";

function signPayload(payload, secret) {
  const canonical = Object.keys(payload)
    .sort()
    .map((key) => `${key}=${payload[key]}`)
    .join("&");

  return crypto
    .createHmac("sha256", secret)
    .update(canonical, "utf8")
    .digest("hex");
}

export async function createPayment(order) {
  const payload = {
    merchant_id: process.env.EASYPAY2_MERCHANT_ID,
    order_id: order.id,
    amount: order.amountMinor,
    currency: order.currency,
    return_url: "https://example.com/payment/return",
    notify_url: "https://example.com/webhooks/easypay2",
    timestamp: Math.floor(Date.now() / 1000)
  };

  const signature = signPayload(
    payload,
    process.env.EASYPAY2_API_SECRET
  );

  const response = await fetch(
    process.env.EASYPAY2_CREATE_PAYMENT_URL,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${process.env.EASYPAY2_API_KEY}`,
        "X-Signature": signature
      },
      body: JSON.stringify(payload),
      signal: AbortSignal.timeout(10000)
    }
  );

  if (!response.ok) {
    throw new Error(`Payment API returned HTTP ${response.status}`);
  }

  return response.json();
}

示例使用 HMAC-SHA256 展示一种常见的签名结构。Easy Pay2 实际采用的可能是 RSA、证书、OAuth 2.0、字段拼接签名或其他认证方式,必须严格遵循官方规范。以下内容尤其不能自行假定:

  • 参数名称和大小写
  • JSON 或表单编码方式
  • 金额是元还是分
  • 时间戳单位
  • 字段排序规则
  • 签名字符集
  • 签名结果是 Hex 还是 Base64
  • 密钥放在 Header 还是请求体中

4. 将用户引导至支付页面

如果创建支付接口返回托管收银台地址,后端应先验证返回结果,再把地址交给前端跳转。

const result = await createPayment(order);

if (!result.payment_url) {
  throw new Error("Payment gateway did not return payment_url");
}

// 将 payment_url 返回给前端,由前端执行跳转

不要直接信任未经验证的跳转地址。可以根据官方生产域名设置允许列表,降低开放重定向和钓鱼风险。

5. 处理异步支付通知

浏览器回跳只能用来展示结果,不能作为订单支付成功的最终依据。用户可能在回跳前关闭页面,回跳参数也可能被伪造。订单状态应以通过验签的 Webhook 为准,必要时再调用订单查询接口复核。

下面的代码仍然只是通用结构。Header、原始请求体的处理方式和验签算法,都必须以官方文档为准。

import crypto from "node:crypto";
import express from "express";

const app = express();

app.post(
  "/webhooks/easypay2",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    const receivedSignature = req.get("X-Signature") ?? "";

    const expectedSignature = crypto
      .createHmac("sha256", process.env.EASYPAY2_WEBHOOK_SECRET)
      .update(req.body)
      .digest("hex");

    const received = Buffer.from(receivedSignature, "utf8");
    const expected = Buffer.from(expectedSignature, "utf8");

    if (
      received.length !== expected.length ||
      !crypto.timingSafeEqual(received, expected)
    ) {
      return res.status(401).send("invalid signature");
    }

    const event = JSON.parse(req.body.toString("utf8"));

    // 同一事件可能重复发送,必须按 event_id 或交易号做幂等处理。
    // 更新订单前还要核对订单号、金额、币种和商户号。
    await processPaymentEvent(event);

    return res.status(200).send("ok");
  }
);

有些框架会默认先解析 JSON,这可能改变用于验签的请求体。如果官方签名以原始请求字节为准,就必须保留 raw body,否则即使密钥正确,验签也可能失败。

6. 查询并确认订单状态

Webhook 超时、订单状态不明确或用户主动返回网站时,可以调用订单查询接口。在确认支付成功前,至少需要核对:

merchant_id
order_id
gateway_transaction_id
amount
currency
payment_status

只有支付状态明确为成功,且商户号、订单号、金额和币种全部匹配,才能把本地订单更新为已支付。

订单处理必须保证幂等

支付通知可能因网络超时而重复发送。同一个支付事件无论到达多少次,都只能触发一次发货、充值或权益开通。

常见的处理方式如下:

  1. 使用本地订单号或网关事件编号建立唯一约束。
  2. 在数据库事务中锁定订单。
  3. 检查订单当前状态是否已经是 PAID。
  4. 核对金额、币种和交易号。
  5. 更新订单状态并记录事件。
  6. 等事务提交后再触发发货流程。

不要使用内存变量去重。应用重启或采用多实例部署后,内存中的去重状态会失效。

安全与上线注意事项

  • API Secret、私钥和证书只能保存在服务端,不能写入 JavaScript 前端代码,也不能提交到代码仓库。
  • 所有支付接口和 Webhook 都必须使用 HTTPS。
  • 日志中不要记录完整密钥、银行卡数据、身份证件或完整支付请求。
  • Webhook 除了验签,还要核对订单金额、币种和商户号。
  • 支付失败后不要无限重试创建订单,以免产生重复交易。
  • 外部请求需要设置连接超时、读取超时,并限制退避重试次数。
  • 如果请求已经发出,但响应超时,应先查询原订单,不能立即创建新订单。
  • 测试环境和生产环境的地址、密钥及数据库记录必须严格隔离。
  • 上线前需要覆盖支付成功、失败、取消、超时、重复通知、退款和金额不一致等场景。
  • 如果接入方式会直接处理银行卡数据,应先确认 PCI DSS 等适用的合规要求,不能仅凭技术接口上线。

找不到官方资料时怎么办

如果 Easy Pay2 的销售方、合同方或技术支持无法提供可验证的官方文档,就不具备安全接入所需的基本条件。此时应暂停开发,不要采用第三方博客提供的未知接口地址或所谓“通用密钥”。

可以通过以下信息继续确认服务商身份:

  • 签约合同中的公司全称
  • 商户后台的正式域名
  • 收款页面显示的品牌和法律主体
  • 开户邮件中的技术支持地址
  • 现有插件或 SDK 的发布者、包名和代码仓库
  • 银行或收单机构提供的产品编号

拿到文档后,重点确认创建支付请求、签名、异步通知和订单查询四部分。只要提供官方文档中的接口定义和脱敏示例,就能据此编写准确的适配代码。在此之前,任何声称可以直接使用的 Easy Pay2 API 地址或参数,都可能是虚构内容,并带来资金安全风险。

备注:内容仅供参考。