Core concepts基础约定
Conventions通用约定
Transport, response envelope, amounts, time, idempotency and versioning.传输、响应格式、金额与时间、幂等与版本。
Transport传输
| Item项 | Rule规则 |
|---|---|
| Protocol协议 | HTTPS only (TLS 1.2+).只用 HTTPS(TLS 1.2 及以上)。 |
| Method方法 | POST for every endpoint, except GET /merchant/v1/health.所有接口都是 POST,只有 GET /merchant/v1/health 例外。 |
| Body正文 | Content-Type: application/json; charset=utf-8. One JSON object. Max request body 1 MiB.Content-Type: application/json; charset=utf-8,正文是一个 JSON 对象,最大 1 MiB。 |
| Wallet URL钱包地址 | <callbackUrl>/<action> with any trailing / of callbackUrl removed, e.g.<callbackUrl>/<动作>,callbackUrl 末尾的 / 先去掉,如 https://wallet.example.com/live/debit |
| HTTP statusHTTP 状态 | Every business result is HTTP 200 with the result in code. HTTP 4xx/5xx means transport or infrastructure failure and is treated as result unknown.所有业务结果都是 HTTP 200,结果看 code。HTTP 4xx / 5xx 表示传输或基础设施故障,按结果未知处理。 |
| Unknown fields未知字段 | Both sides must ignore fields they do not recognise, in requests and responses.双方对不认识的字段(请求和响应里)必须忽略,不报错。 |
| Strings字符串 | Leading/trailing whitespace is trimmed before validation. An empty string is the same as not sent.校验前去掉两端空白;空串等于没传。 |
Response envelope响应格式
{
"code": "OK",
"message": "OK",
"data": { }
}
codestring
Result code (Result codes). Programs decide only on
code.结果码(结果码)。程序只按 code 判断。messagestring
English text for developers and logs, may name the offending field. Not stable; never parse it, never show it to players — map
code to your own localized text.给开发和日志看的英文说明,可能带出错字段名。不保证稳定:不要解析它,也不要直接展示给玩家——请按 code 映射成自己的多语言文案。dataobject
Result on success. Some failures also carry data (for example the current
balance on INSUFFICIENT_BALANCE); each endpoint says when. Otherwise omitted.成功时的结果。部分失败也带数据(如 INSUFFICIENT_BALANCE 带当前 balance),各接口会写明;否则省略。Amounts & time金额与时间
| Item项 | Rule规则 |
|---|---|
| Amount format金额格式 | Decimal string matching ^\d{1,15}(\.\d{1,4})?$: no sign, exponent or thousands separator. Always ≥ 0; direction is given by the transaction type.十进制字符串,匹配 ^\d{1,15}(\.\d{1,4})?$:没有正负号、科学计数法、千分位。恒 ≥ 0,方向由交易类型表达。 |
| Precision精度 | Decimal places must not exceed the currency precision (USD 2, IDR 0, USDT 4 …). Too many places → INVALID_PARAM, never rounded. Senders pad to the currency precision ("10.00", not "10"); receivers compare numerically.小数位不超过币种精度(USD 2 位、IDR 0 位、USDT 4 位……)。超了返回 INVALID_PARAM,不做四舍五入。发送方补齐到币种精度(发 "10.00" 而不是 "10"),接收方按数值比较。 |
| Arithmetic计算 | Use decimal / fixed-point types. Never binary floating point.用 Decimal / 定点数,绝不用二进制浮点。 |
| Currency币种 | Uppercase code from the agreed list (e.g. USD, EUR, BRL, IDR, INR, USDT). One extPlayerId has exactly one currency forever.双方约定列表里的大写代码(如 USD、EUR、BRL、IDR、INR、USDT)。一个 extPlayerId 永远只有一种币种。 |
| Time in body正文里的时间 | RFC 3339 in UTC with milliseconds, e.g.RFC 3339、UTC、带毫秒,如 "2026-10-13T08:00:00.123Z" |
| Signing time签名时间 | Only in X-Timestamp, epoch milliseconds.只在请求头 X-Timestamp,毫秒时间戳。 |
| Day boundary日切 | Reconciliation uses UTC days.对账按 UTC 自然日。 |
Idempotency幂等
Must必须
On your Wallet API,
txnId is the idempotency key. Enforce a database unique constraint on (merchantCode, txnId).
商户钱包接口以 txnId 为幂等键,在 (merchantCode, txnId) 上建数据库唯一约束。
- Same
txnId, same content → return the first result unchanged — success or failure — with the samemerchantTxnId, and do not move money again. - Same
txnId, different content (amount, player, round, type, reference) →TXN_CONFLICT; the first result stays. - A failed debit stays failed: if the first answer was
INSUFFICIENT_BALANCE, a retry after the player tops up must still answerINSUFFICIENT_BALANCE. - Write the balance change and the transaction record in one database transaction.
- 同一
txnId、内容相同 → 原样返回第一次的结果(成功或失败都一样),merchantTxnId相同,不再动钱。 - 同一
txnId、内容不同(金额、玩家、局、类型、引用)→TXN_CONFLICT,第一次的结果不变。 - 失败的扣款永远是失败:第一次返回
INSUFFICIENT_BALANCE,玩家充值后同一笔重发,仍然返回INSUFFICIENT_BALANCE。 - 改余额与写交易记录放在同一个数据库事务里。
On our side, games/launch and rounds/report-url issue a new one-time URL on every call; calling twice only gives you two URLs.
平台的 games/launch 与 rounds/report-url 每次调用都签一个新的一次性地址,重复调只是多拿一个地址。
Versioning版本
- Backward-compatible changes do not bump the version: new optional request fields, new response fields, new result codes. Treat an unknown result code as
INTERNAL_ERROR. - Version
1is the only version today. A breaking change would ship as version2under/merchant/v2, announced in advance; version 1 keeps working until you move.
- 向后兼容的改动不升版本:新增可选请求字段、新增响应字段、新增结果码。遇到不认识的结果码按
INTERNAL_ERROR处理。 - 目前只有第
1版。将来若有不兼容的改动,以第2版发布(路径/merchant/v2)并提前通知;商户切换之前第 1 版照常可用。