Skip to content

5 分钟接入 ​

这一页只做一件事:让你在最短时间里收到第一笔钱,并在自己的服务端上看到回调。 下面的示例里 API_BASE 指你的接入域名(例如 https://api.web3sdk.com,实际以接入时获得的地址为准)。

第 0 步:拿到 API KEY ​

通过官网注册入口提交商户资料,平台开通后为你的商户号签发 API KEY。

自助注册已开放

API KEY 不随注册响应下发。注册完成后登录商户后台,在「支付收款 → 支付设置」里点「查看」 即可看到当前明文(每次查看都会记审计,平台也不会把 KEY 写进邮件)。 要换 KEY 在同一页点「重置」,旧 KEY 在过渡期后失效。

拿到之后把 KEY 存在服务端的环境变量里,不要写进代码仓库、不要放进前端:

bash
export PAY_API_KEY='<你的 API KEY>'
export API_BASE='https://api.web3sdk.com'

平台侧的商户接口 GET /api/pay/getMyProfile 会返回你的 merchantNo、collectName、 脱敏后的 apiKey 与 cashierBaseUrl。KEY 的明文请到商户后台「支付收款 → 支付设置」查看 (单独接口、每次记审计;getMyProfile 永远只回末 4 位)。

第 1 步:配置收款地址 ​

在商户后台登录后,为一条已授权的链填收款地址并设为启用。商户侧接口:

http
GET {API_BASE}/api/pay/getMyChains

拿到可用链与代币的 id 之后(收银页可用同一份清单):

bash
curl -X POST "$API_BASE/api/pay/saveMyAddress" \
  -H 'Content-Type: application/json' \
  -H 'x-token: <商户后台登录后的 JWT>' \
  -d '{
    "chainId": 2,
    "address": "TXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "label": "主收款地址"
  }'

再把它设为启用:

bash
curl -X POST "$API_BASE/api/pay/setActiveAddress" \
  -H 'Content-Type: application/json' \
  -H 'x-token: <商户后台登录后的 JWT>' \
  -d '{"chainId": 2, "address": "TXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}'

收款地址决定钱去哪儿

下单时平台会把当时启用的那个地址锁定进订单快照。之后你换地址,不会影响已经创建的订单 —— 买家仍按老地址转账,系统也仍然监听它。

第 2 步:服务端创建订单 ​

在你自己的服务端调用开放接口。请求头带 API KEY,字段里的 amount 是代币单位的小数字符串:

bash
curl -X POST "$API_BASE/api/pay/open/createOrder" \
  -H "X-Pay-Api-Key: $PAY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "merchantOrderNo": "SHOP-2026-0001",
    "chainId": 2,
    "tokenId": 1,
    "amount": "100.5",
    "subject": "订单 SHOP-2026-0001",
    "notifyUrl": "https://your-shop.com/pay/notify",
    "returnUrl": "https://your-shop.com/pay/done"
  }'

响应(节选):

json
{
  "code": 0,
  "data": {
    "order": {
      "orderNo": "PO20261011XXXXXXXXXXXX",
      "merchantOrderNo": "SHOP-2026-0001",
      "merchantNo": "M00000XXXX",
      "status": 1,
      "statusText": "待支付",
      "orderType": 1,
      "amountMinimal": "100500000",
      "payAmountMinimal": "100500123",
      "payAmountDisplay": "100.500123",
      "payAddress": "TXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "chainId": 2,
      "tokenId": 1,
      "identify": {
        "mode": 1,
        "orderNo": "PO20261011XXXXXXXXXXXX",
        "calldataSuffix": "0x...订单识别码..."
      }
    },
    "idempotentReplay": false
  },
  "msg": "下单成功"
}

三个金额字段的分工要记住:

  • amountMinimal —— 你下单时给的金额(最小单位)。
  • payAmountMinimal —— 实际应该转的金额。当识别方式是"金额尾数"时会比上面多一段尾数。以它为准。
  • payAmountDisplay —— 上面那个给人看的形式。

identify 是这笔订单的识别信息,必须原样透传,不要改大小写、不要加前缀,否则扫块时认不出这一单。

第 3 步:买家扫码付款 ​

把你的收款台链接或二维码给买家。收款台地址的形状是:

{cashierBaseUrl}/pay/cashier/m/{merchantNo}

cashierBaseUrl 与 merchantNo 都来自 GET /api/pay/getMyProfile。 注意商户号是路径段而不是查询串 —— 查询串会被部分钱包的深链按 = 截断。

买家打开后,收银页会调这几个公开接口(无需登录):

GET  /api/pay/getCashierMerchant     # 收款名称等展示信息
GET  /api/pay/getCashierChains       # 可用的链与代币清单(脱敏)
GET  /api/pay/getCashierOrder        # 按订单号查这一单
POST /api/pay/createCashierOrder     # 线下扫码:买家先输金额再下单
POST /api/pay/submitCashierTxHash    # 买家签名后回传交易哈希

如果你是从自己的系统推过来的订单(线上单),让买家直接进 getCashierOrder 对应的收银页即可, 不需要再走 createCashierOrder。

第 4 步:收回调并改单 ​

确认数达标后,平台会 POST 到你配置的(或本单 notifyUrl 指定的)地址。先校验签名,再处理业务:

go
// 关键:验签用的是**你自己的 API KEY**,报文体用**原始字节**,不要先解析再重编码
func verify(apiKey, ts, rawBody, sig string) bool {
    mac := hmac.New(sha256.New, []byte(apiKey))
    mac.Write([]byte(ts))
    mac.Write([]byte(rawBody))
    want := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(want), []byte(sig))
}

func handler(w http.ResponseWriter, r *http.Request) {
    raw, _ := io.ReadAll(r.Body)
    ts := r.Header.Get("X-Pay-Timestamp")
    sig := r.Header.Get("X-Pay-Signature")
    if !verify(os.Getenv("PAY_API_KEY"), ts, string(raw), sig) {
        http.Error(w, "bad signature", http.StatusUnauthorized)
        return
    }
    var p struct {
        MerchantOrderNo string `json:"merchantOrderNo"`
        OrderNo         string `json:"orderNo"`
        Status          int    `json:"status"`
        ReceivedAmount  string `json:"receivedAmount"`
        TxHash          string `json:"txHash"`
    }
    _ = json.Unmarshal(raw, &p)

    // 幂等:同一个 merchantOrderNo 只处理一次,回调会重试
    if alreadyDone(p.MerchantOrderNo) {
        w.WriteHeader(http.StatusOK) // 2xx 才会让平台停止重试
        return
    }
    markPaid(p.MerchantOrderNo, p.TxHash, p.ReceivedAmount)
    w.WriteHeader(http.StatusOK)
}

处理完之后:

  • 返回 2xx 表示你收到了,平台不会再重试。
  • 返回其它状态码或不响应,平台会按退避序列重试。
  • 不要只依赖回调:任何时刻都可以用查询接口主动核对真实状态。
bash
curl "$API_BASE/api/pay/open/queryOrder?merchantOrderNo=SHOP-2026-0001" \
  -H "X-Pay-Api-Key: $PAY_API_KEY"

到这里,一笔钱就走完了。接下来可以按你的形态挑一条更细的路径:

创建订单

字段、金额约定、幂等键的完整说明。

回调通知与验签

重试序列、幂等、以及为什么要以查询为准。

术语与概念

把上面出现的名词一次补齐。

面向全球中小商家的 Web3 支付基础设施