GaaPay 接入文档

GaaPay 是面向站群的虚拟币收款基础设施。你创建一个订单,用户在我们的收银台完成链上转账,我们负责监听、确认、入账、分账与对账,并通过签名 Webhook 通知你发货。

API v1 HMAC-SHA256 鉴权 幂等下单 至少一次投递

5 分钟接入

  1. 控制台 → 应用与密钥 → 创建应用,拿到 AppID 与 sk_test_… 密钥(仅显示一次)。
  2. 服务端调用 POST /api/v1/orders 创建订单,拿到 checkout_url。
  3. 把用户重定向到 checkout_url,或把链接直接发给用户。
  4. 接收 Webhook payment.succeeded,验签通过后再发货。
# 1) 下单(签名见下一节)
curl -X POST https://api.gaapay.com/api/v1/orders \
  -H "content-type: application/json" \
  -H "x-gaapay-app: app_xxx" \
  -H "x-gaapay-timestamp: 1792596770" \
  -H "x-gaapay-nonce: 3f1c9a2e" \
  -H "x-gaapay-signature: 9d1f…" \
  -d '{"amount":"19.90","merchant_order_ref":"order_20261021_001","description":"至尊月卡 · 30 天"}'

# 2) 响应
{
  "object": "order",
  "id": "ord_01m5f…",
  "short_code": "GP-20261021-8F3A2C",
  "status": "QUOTED",
  "amount": 19.9,
  "checkout_url": "https://checkout.gaapay.com/pay/VCCC…",
  "expires_at": "2026-10-21T14:46:56.632Z"
}
沙箱:当 MODE=sandbox 时,收银台会出现「沙箱控制台」,可一键触发正常支付、少付、多付、逾期、错链、错币、reorg、风控冻结八类场景,全部走与生产相同的入账管线。

核心概念

理解三个模型,你就能理解整套系统为什么这样设计。

这样设计的好处:新增链或渠道不会改动订单与账本;用户切换支付方式不会产生两笔订单,对账不会混乱。

鉴权与签名

所有商户 API 请求都必须携带四个头。签名原文按行拼接,顺序不可变:

payload = timestamp + "\n" + nonce + "\n" + METHOD + "\n" + path + "\n" + raw_body
signature = hex( HMAC_SHA256(app_secret, payload) )
// Node.js
import { createHmac, randomUUID } from 'node:crypto';

function signedFetch(path, body) {
  const ts = Math.floor(Date.now() / 1000);
  const nonce = randomUUID();
  const raw = body ? JSON.stringify(body) : '';
  const sig = createHmac('sha256', process.env.GAAPAY_SECRET)
    .update([ts, nonce, body ? 'POST' : 'GET', path, raw].join('\n'))
    .digest('hex');
  return fetch(`https://api.gaapay.com${path}`, {
    method: body ? 'POST' : 'GET',
    headers: {
      'content-type': 'application/json',
      'x-gaapay-app': process.env.GAAPAY_APP,
      'x-gaapay-timestamp': String(ts),
      'x-gaapay-nonce': nonce,
      'x-gaapay-signature': sig,
    },
    body: raw || undefined,
  });
}
# Python
import hmac, hashlib, time, uuid, json

def sign(method, path, body: str, secret: str):
    ts, nonce = str(int(time.time())), str(uuid.uuid4())
    payload = f"{ts}\n{nonce}\n{method}\n{path}\n{body}"
    sig = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
    return {"x-gaapay-timestamp": ts, "x-gaapay-nonce": nonce, "x-gaapay-signature": sig}
<?php
$ts = time(); $nonce = bin2hex(random_bytes(8)); $raw = json_encode($body);
$payload = $ts."\n".$nonce."\nPOST\n".$path."\n".$raw;
$sig = hash_hmac('sha256', $payload, $secret);
// headers: x-gaapay-app / x-gaapay-timestamp / x-gaapay-nonce / x-gaapay-signature

零代码接入(L0 / L1)

没有后端也能收款:控制台生成收款链接,打开即进入收银台。适合静态站、活动页、社群直发、客服手动开单。

限制(必须知道):无代码接入不经过你的服务器,因此无法自动发货。两条可用路径:① 人工确认后发货;② 配置「带签名参数的支付成功回跳地址」,由你的站点验签后发货。

创建订单

POST /api/v1/orders

参数类型必填说明
amountstring是USD 金额,最多 6 位小数。不要用浮点数拼接。
merchant_order_refstring是你的订单号。与 AppID 联合唯一,是天然的幂等键:重复提交返回同一订单。
descriptionstring否展示给用户,如「至尊月卡 · 30 天」。
merchant_user_refstring否不透明用户标识(如 u_10231)。用于超额/逾期入账归属与日限额统计。禁止传邮箱、手机号等可识别个人信息。
metadataobject否任意键值,原样回传。
redirect_ok / redirect_failstring否支付成功 / 失败后的回跳地址。
template_idstring否场景模板 T1–T9,一次性覆盖十几个参数(锁价、容差、结算周期…)。
overridesobject否单笔订单的参数覆盖,最高优先级。安全类参数受方向锁约束。
split_rule_idstring否分账规则 ID。订单会快照当时的规则版本。

查询 / 取消 / 退款

接口说明
GET /api/v1/orders/:id按 GaaPay 订单 ID 查询,含全部 Attempt 与报价快照。
GET /api/v1/orders?merchant_order_ref=…按你自己的订单号查询。建议在 Webhook 丢失时用它兜底。
POST /api/v1/orders/:id/cancel仅未到账的订单可取消。
POST /api/v1/orders/:id/refund退款只能退回原付款地址;指定其他地址会被拒绝。超过阈值需第二人审批。
GET /api/v1/ping验签自检 + 环境确认。
GET /api/v1/config查看当前生效配置与来源层(provenance)。

错误码

codeHTTP含义与处置
INVALID_REQUEST400参数错误。不重试,修正后重新提交。
INVALID_SIGNATURE401签名不匹配。检查拼接顺序与 raw_body 是否与发送时完全一致。
TIMESTAMP_OUT_OF_WINDOW401时间戳偏差 > 5 分钟。校时后重试。
NONCE_REPLAY401同一 nonce 被复用。每次请求必须新生成。
RISK_BLOCKED403命中风控(限额 / 速度 / 名单)。可联系支持复核。
AMOUNT_TOO_SMALL400低于该商户或该链的最低金额。
CHAIN_DISABLED400商户未开启该网络。
CHANNEL_UNAVAILABLE503渠道暂时不可用。路由会尝试备选渠道;必要时降级到 Rail B。
ORDER_NOT_PAYABLE409订单当前状态不可支付(已付、已取消等)。
IDEMPOTENT_INFLIGHT409相同幂等键的请求正在处理中,稍后重试即可。

所有错误响应都带 request_id。提工单时提供它即可精确定位到那一次调用。

事件目录

事件是否可发货说明
order.created否订单创建。
payment.detected否mempool / 首次检出。仅体验信号,绝不能据此发货。
payment.succeeded是达到放行条件。唯一的发货依据。
payment.settled—达到最终确认数,资金转入已确认金库。
payment.underpaid否少付,携带已收与差额。地址继续监听,支持多笔补齐。
payment.overpaid是多付,超额部分按配置入余额,绝不吞币。
payment.late否订单过期后到账,按当前汇率折算入余额。
payment.reorged—链上回滚,你需要撤销发货或计入坏账。
payment.risk_hold否风控冻结,转人工。
refund.succeeded—退款完成。

验签实现(必须做)

签名串为 timestamp + "." + body,算法 HMAC-SHA256,头信息:

x-gaapay-event: payment.succeeded
x-gaapay-event-id: evt_01m5f…
x-gaapay-timestamp: 1792596770
x-gaapay-signature: v1=9d1f…
x-gaapay-delivery: 1
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyGaaPayWebhook({ secret, timestamp, body, signature }) {
  // 防重放:时间戳偏差超过 5 分钟直接拒绝
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = 'v1=' + createHmac('sha256', secret).update(`${timestamp}.${body}`).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature || '');
  return a.length === b.length && timingSafeEqual(a, b);
}
三个必须:① 必须验签,否则任何人都能伪造「支付成功」白嫖;② 必须按 event_id 幂等消费,投递是「至少一次」;③ 必须以 payment.succeeded 为准,不要相信前端回跳参数。

重试与死信

非 2xx 或 10 秒超时即视为失败,按指数退避重试:10s → 30s → 2m → 10m → 1h → 6h → 24h(共 7 次,跨度约 32 小时)。全部失败进入死信队列,控制台可手动重投。

不保证顺序。请以事件中的状态与版本为准,而不是到达顺序;重复投递携带相同 event_id。

对账 · 结算 · 分账

对账

每天 UTC 00:00 日切。两条独立口径:链上事实重新累加 vs 账本分录直接求和。差异分级:漏单/多记/金额差为 P0(自动冻结出款),悬账为 P1,状态差 P2,跨日时间差 P3 自动消解。

结算

站群内部划转全部在账本内完成,不产生任何链上交易:T+0/T+1/T+3 可配,pending → available 只是一条分录,零 Gas、即时、不会失败。只有当资金需要离开 GaaPay 体系时才上链。

分账

求值顺序:固定金额 → 固定比例 → 阶梯比例 → 剩余分配(residual)。每条规则必须且只能有一个 residual 方承接尾差;各方之和必须严格等于净额,否则拒绝执行并告警。

安全实践清单

服务条款(摘要)

GaaPay 提供的是软件与监控服务:地址派生、链上监听、确认、记账、通知、对账与报表。GaaPay 不保管、不代付、不划转商户资金;自托管模式下资金直达商户登记的收款地址,私钥由商户自行持有并承担其业务的合规责任。

商户对其业务的合法性、商品交付、税务与用户协议独立负责。加密资产转账不可撤销,商户应在发货前完成自身风控判断。

本段为摘要。具有约束力的完整文本见 《服务条款》,两者不一致时以完整文本为准。

隐私政策(摘要)

我们只采集完成支付所必需的数据:商户标识、订单号、金额、币种、链、地址、交易哈希、时间戳与状态。我们不采集玩家姓名、邮箱、手机号、证件或支付卡信息,也不做设备指纹画像。数据库中不含可识别个人身份的信息集合。

完整的数据类别、处理基础、保存期限与跨境传输说明见 《隐私政策》。

退款政策(摘要)

加密支付无拒付(chargeback),退款需由商户主动发起并承担链上 Gas。退款只退回原付款地址;若原地址不可用,资金退回商户待结算余额,由商户自行与其用户协商。退款审批遵循发起人 ≠ 审批人的四眼原则。

少付/多付/错链的自动化分流规则与争议举证流程见 《退款与争议处理政策》。

文档版本 v0.1 · 与 GaaPay 服务端 API v1 对应 · 破坏性变更会提前 90 天通知