Integration Requirements Document — GM Tool Side
Version: 1.0 | Date: 2026-04-28
1. Objective
After each item grant to a player's account, the GM Tool must send a log record to the central system via API. A single request can contain multiple items (batch items) in one transaction.
2. Required Information
Before integration, contact the Admin to receive:
| Information | Description | Example |
|---|---|---|
API_KEY | GM Tool's specific API key | gmtool_abc123xyz |
GAME_ID | Game identifier | game_rpg_01 |
BASE_URL | Central System address | https://central.vgp.com |
3. Mandatory Flow
Step 1: GM grants items in the game
Step 2: Receive the result (success / failure)
Step 3: Call POST /api/gm/grant-log (asynchronous, do not block UI)
Step 4: If API fails → retry up to 3 times
Step 5: If it still fails → log locally for later processing
Note: Call the API in Step 3 regardless of whether the result is a success or failure.
4. API Call
Endpoint
POST {BASE_URL}/api/gm/grant-log
Headers
Content-Type: application/json
Authorization: Bearer {API_KEY}
X-Game-ID: {GAME_ID}
Request Body
{
"gm_account": "gm_vana",
"gm_name": "Nguyen Van A",
"game_id": "game_rpg_01",
"vgpid": 8821043,
"granted_at": "2026-04-28T10:05:32+07:00",
"status": "success",
"reason": "Server error compensation",
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
"items": [
{
"item_id": "item_diamond_001",
"item_name": "Diamond",
"quantity": 500
},
{ "item_id": "item_gold_001", "item_name": "Gold", "quantity": 1000 }
]
}
Field Descriptions — Transaction Level
| Field | Type | Required | Description |
|---|---|---|---|
gm_account | string | ✅ | GM username logged into the tool |
gm_name | string | ✅ | Display name of the GM |
game_id | string | ✅ | Game code (from Admin) |
vgpid | long | ✅ | VGPID of the player receiving the grant |
granted_at | string (ISO 8601) | ✅ | Execution time, with timezone +07:00 |
status | string | ✅ | "success" or "failed" |
reason | string | Reason for the grant | |
idempotency_key | UUID v4 | ✅ | Generate a new one for each execution |
items | array | ✅ | List of items (≥ 1 element) |
Field Descriptions — Each items[] Element
| Field | Type | Required | Description |
|---|---|---|---|
item_id | string | ✅ | Item code in the game system |
item_name | string | Item name (for display) | |
quantity | integer | ✅ | Granted quantity (> 0) |
idempotency_key: Generate a new UUID v4 for each execution. Used for safe retries — if called again with the same key, the server returns 409 and ignores it to prevent duplicate records.items: Minimum 1 element. Maximum 50 elements per request.
5. Response Handling
| HTTP Status | Meaning | Action |
|---|---|---|
200 OK | Recorded successfully | Continue normally |
409 Conflict | idempotency_key already exists | Ignore — safe, no duplicate record |
400 Bad Request | Invalid payload / missing fields | Recheck data, log error |
401 Unauthorized | Invalid or expired API key | Notify Admin immediately |
5xx / Timeout | Server / Network error | Retry according to section 6 |
6. Retry on Error
1st time: retry after 30 seconds
2nd time: retry after 60 seconds
3rd time: retry after 120 seconds
→ Still failing: log to local log (see section 7)
- Timeout for each call: 5 seconds
- Run asynchronously (background), do not block the GM screen
7. Local Log When API Fails
If it still fails after 3 retries, log it to a local file/DB with the full payload for later reconciliation:
{
"timestamp": "2026-04-28T10:05:40+07:00",
"error": "connection timeout",
"payload": { ... }
}
8. Sample Code (Python)
import uuid, asyncio, httpx
from datetime import datetime, timezone, timedelta
BASE_URL = "https://central.vgp.com"
API_KEY = "gmtool_abc123xyz"
GAME_ID = "game_rpg_01"
VN_TZ = timezone(timedelta(hours=7))
async def report_grant(gm_account, gm_name, vgpid,
items: list,
status, reason=None):
"""
items: [{ "item_id": str, "item_name": str, "quantity": int }, ...]
"""
payload = {
"gm_account": gm_account,
"gm_name": gm_name,
"game_id": GAME_ID,
"vgpid": vgpid,
"granted_at": datetime.now(VN_TZ).isoformat(),
"status": status,
"reason": reason,
"idempotency_key": str(uuid.uuid4()),
"items": items,
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"X-Game-ID": GAME_ID,
"Content-Type": "application/json",
}
delays = [30, 60, 120]
for delay in [0] + delays:
if delay:
await asyncio.sleep(delay)
try:
async with httpx.AsyncClient(timeout=5.0) as client:
r = await client.post(
f"{BASE_URL}/api/gm/grant-log",
json=payload, headers=headers
)
if r.status_code in (200, 409):
return True
if r.status_code == 401:
# Notify Admin, do not retry
_write_local_log("auth_error", payload)
return False
except Exception as e:
pass # continue retry
_write_local_log("max_retry_exceeded", payload)
return False
def _write_local_log(error, payload):
# Log to a local file or DB
pass
9. Pre-Go-Live Checklist
- Received
API_KEY,GAME_ID,BASE_URLfrom Admin - Tested with staging environment
- Confirmed
granted_atis in correct ISO 8601 format with+07:00 - Confirmed
vgpidis of long (integer) type, not a string - Confirmed
idempotency_keyis a new UUID v4 for each execution - Confirmed API is called asynchronously, without blocking UI
- Implemented local logging mechanism for API failures