Skip to main content

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:

InformationDescriptionExample
API_KEYGM Tool's specific API keygmtool_abc123xyz
GAME_IDGame identifiergame_rpg_01
BASE_URLCentral System addresshttps://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

FieldTypeRequiredDescription
gm_accountstringGM username logged into the tool
gm_namestringDisplay name of the GM
game_idstringGame code (from Admin)
vgpidlongVGPID of the player receiving the grant
granted_atstring (ISO 8601)Execution time, with timezone +07:00
statusstring"success" or "failed"
reasonstringReason for the grant
idempotency_keyUUID v4Generate a new one for each execution
itemsarrayList of items (≥ 1 element)

Field Descriptions — Each items[] Element

FieldTypeRequiredDescription
item_idstringItem code in the game system
item_namestringItem name (for display)
quantityintegerGranted 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 StatusMeaningAction
200 OKRecorded successfullyContinue normally
409 Conflictidempotency_key already existsIgnore — safe, no duplicate record
400 Bad RequestInvalid payload / missing fieldsRecheck data, log error
401 UnauthorizedInvalid or expired API keyNotify Admin immediately
5xx / TimeoutServer / Network errorRetry 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_URL from Admin
  • Tested with staging environment
  • Confirmed granted_at is in correct ISO 8601 format with +07:00
  • Confirmed vgpid is of long (integer) type, not a string
  • Confirmed idempotency_key is a new UUID v4 for each execution
  • Confirmed API is called asynchronously, without blocking UI
  • Implemented local logging mechanism for API failures