Download OpenAPI specification:
Server-to-server API that the game server implements and the GAGA backend calls. It lets GAGA look up servers and characters by GAGA ID, and deliver purchased items (G Coin first) to a character's in-game mailbox.
中文摘要:本 API 由遊戲伺服器實作,由 GAGA 後端呼叫(伺服器對伺服器)。 用途:查詢伺服器列表、用 GAGA ID 查角色、把購買的道具(先從 G Coin 開始)寄到角色信箱。 與 GAGA SDK、遊戲客戶端、Google Play / App Store 內購無關。
First consumer: Funtap (VN) web top-up. The player pays on nap.funtap.games;
Funtap calls the GAGA backend; the GAGA backend calls this API.
| Step | Caller → Callee | API |
|---|---|---|
| 1 | Funtap → GAGA BE | Get servers (Funtap S2S) |
| 1a | GAGA BE → Game server | GET /servers |
| 2 | Funtap → GAGA BE | Find role by account_id (Funtap S2S) |
| 2a | GAGA BE → Game server | GET /roles |
| 3 | Player pays on Funtap | — |
| 4 | Funtap → GAGA BE | Payment notification → GAGA verifies with Funtap inquiry |
| 5 | GAGA BE → Game server | POST /mails — G Coin to mailbox |
| 6 | GAGA BE → Game server (only on timeout / 5xx) | GET /mails/{invoice_id} |
The same contract will be reused later for GAGA Web Shop direct delivery
(other item types in items[]), so implement items as a list, not a single G Coin field.
Field names follow the Funtap S2S guide (v2.7) on purpose — server_id, server_name,
account_id, role_id, role_name, os, invoice_id, product_id, created_at —
so values pass through GAGA unchanged.
| Funtap S2S v2.7 | This API | |
|---|---|---|
| Auth | client_id + per-endpoint SHA256(secret + params) signature + 5-min timestamp |
X-Client-Id + X-Api-Key headers over HTTPS + IP allowlist. No signature, no timestamp. |
| Response shape | Mixed (raw array / raw object / {code}) |
Always {code, message, data} |
| Find role | Spec says array, example shows object | Always an array |
| Request body (POST) | form-urlencoded | application/json |
| Retry safety | Partner dedupes pay_id |
Game server dedupes invoice_id (see Idempotency) |
Every request carries two headers. Credentials are issued by GAGA, one pair per environment (staging and production never share a key).
| Header | Example | Notes |
|---|---|---|
X-Client-Id |
gaga-xlegend-stg |
Identifies GAGA environment / game |
X-Api-Key |
sk_stg_9f2c… |
Static secret, ≥ 32 chars. Compare in constant time. |
Transport and network rules:
POST /mails creates in-game value, and the API key alone is the only other control.X-Api-Key.Wrong or missing credentials → HTTP 401, code: 401. Source IP not allowed → HTTP 403, code: 403.
All responses are JSON:
{ "code": 200, "message": "OK", "data": { } }
code is an integer and equals the HTTP status (200 on success). There is no code: 0.message is human-readable, English, for logs only. GAGA never parses it.data is present on success; it may be omitted on error.| code | HTTP | Meaning | GAGA retries? |
|---|---|---|---|
| 200 | 200 | Success (also for a duplicate invoice_id — see Idempotency) |
— |
| 400 | 400 | Missing / malformed parameter | No |
| 401 | 401 | Bad X-Client-Id / X-Api-Key |
No |
| 403 | 403 | Source IP not allowed | No |
| 404 | 404 | Account, server, role or invoice not found | No (on GET /mails/{invoice_id}: means not delivered yet) |
| 409 | 409 | Same invoice_id already used with a different payload |
No — alert |
| 422 | 422 | Unknown item_id, bad quantity, or role cannot receive mail |
No — alert |
| 500 | 500 | Unexpected error | Yes |
| 503 | 503 | Server maintenance / temporarily unavailable | Yes |
invoice_id (GAGA's transaction id) is the idempotency key for POST /mails.
invoice_id with a unique constraint in the same transaction that creates the mail.invoice_id + same payload again → do not send another mail; return 200 with the original
mail_id and "duplicate": true.invoice_id + different account_id / server_id / role_id / items → 409.invoice_id records for at least 90 days.GAGA retry behaviour (so you know what to expect):
500 or 503: GAGA first calls GET /mails/{invoice_id}.
If 200 → done. If 404 → GAGA re-sends POST /mails with the same invoice_id.| Field | Format |
|---|---|
account_id |
GAGA ID, canonical form without dashes, 16 chars: THGA284190375216 (display form TH-GA-284190375216). The same value the game server receives as gaga_id from GAGA SDK login. |
*_id |
String. Do not assume numeric. |
created_at, sent_at |
Unix timestamp, seconds, integer. |
quantity |
Integer ≥ 1. |
| Text | UTF-8. role_name may contain CJK / Vietnamese / Thai characters. |
The game server provides two base URLs (staging and production), as Funtap requires separate test and live endpoints. Paths below are fixed; only the base URL changes.
| Env | Base URL (provided by game team) | Credentials (provided by GAGA) |
|---|---|---|
| Staging | https://<stg-host>/gaga/v1 |
X-Client-Id / X-Api-Key (stg) + GAGA stg egress IPs |
| Production | https://<prod-host>/gaga/v1 |
X-Client-Id / X-Api-Key (prod) + GAGA prod egress IPs |
item_id (and any other item_id GAGA may send), with max quantity per mail.Returns every server the player can top up to. Mirrors Funtap S2S 1. Get game server/area.
Include servers under maintenance only if they can still receive mail later; GAGA caches this list for 5 minutes.
{- "code": 200,
- "message": "OK",
- "data": [
- {
- "server_id": "12345",
- "server_name": "Server Vietnam 1"
}, - {
- "server_id": "12346",
- "server_name": "Server Vietnam 2"
}
]
}Returns the characters that a GAGA account has on one server. Mirrors Funtap S2S 2. Find game role, but always returns an array (the player picks one in a dropdown).
404.| account_id required | string^[A-Z]{4}[0-9]{12}$ Example: account_id=VNGA284190375216 GAGA ID, canonical form (no dashes). |
| server_id required | string Example: server_id=12345 |
{- "code": 200,
- "message": "OK",
- "data": [
- {
- "role_id": "2356423",
- "role_name": "Role name ABC",
- "level": 45,
- "os": "android"
}, - {
- "role_id": "2356424",
- "role_name": "小敏",
- "level": 12,
- "os": "ios"
}
]
}Delivers items (e.g. G Coin) as a mail attachment. Called after GAGA has verified the payment with Funtap. Equivalent of Funtap S2S 3. Payment notification, one hop further down.
Idempotent on invoice_id — see Idempotency. The game server must never create
two mails for the same invoice_id.
Validate before sending: role_id belongs to account_id on server_id, and every item_id is known.
Return 200 only after the mail is committed to the database.
| invoice_id required | string <= 64 characters GAGA transaction id. Idempotency key. |
| account_id required | string^[A-Z]{4}[0-9]{12}$ GAGA ID, canonical form. |
| server_id required | string |
| role_id required | string |
| product_id required | string GAGA package id the player bought. For audit only; deliver |
required | Array of objects (Item) [ 1 .. 10 ] items |
| mail_title required | string <= 50 characters |
| mail_content required | string <= 500 characters |
| source required | string Enum: "funtap" "webshop" Sales channel, for the game's own reports. |
| created_at required | integer Payment time, Unix seconds. |
{- "invoice_id": "GW20261002A1B2C3D4",
- "account_id": "VNGA284190375216",
- "server_id": "12345",
- "role_id": "2356423",
- "product_id": "GCOIN_1000",
- "items": [
- {
- "item_id": "900001",
- "quantity": 1100
}
], - "mail_title": "GAGA Top-up",
- "mail_content": "Thank you for your purchase. 1,000 G Coin + 100 bonus.",
- "source": "funtap",
- "created_at": 1790000000
}{- "code": 200,
- "message": "OK",
- "data": {
- "invoice_id": "GW20261002A1B2C3D4",
- "mail_id": "M-88123901",
- "status": "sent",
- "duplicate": false,
- "sent_at": 1790000003
}
}Returns the mail created for an invoice_id. Equivalent of Funtap S2S 4. Payment inquiry.
GAGA calls this when POST /mails timed out or returned 5xx, and during daily reconciliation.
404 here means not delivered — GAGA will then re-send with the same invoice_id.
| invoice_id required | string <= 64 characters Example: GW20261002A1B2C3D4 |
{- "code": 200,
- "message": "OK",
- "data": {
- "invoice_id": "GW20261002A1B2C3D4",
- "mail_id": "M-88123901",
- "status": "claimed",
- "account_id": "VNGA284190375216",
- "server_id": "12345",
- "role_id": "2356423",
- "items": [
- {
- "item_id": "900001",
- "quantity": 1100
}
], - "sent_at": 1790000003,
- "claimed_at": 1790000420
}
}