ZankethStore
Reseller API
Deliver game top-ups through our secure fulfilment platform. One POST โ we handle queuing, balance checks, dispatch, and confirmation.
๐กOverview
The ZankethStore Reseller API lets authorised developers trigger game top-ups via a single HTTP POST. Send a player ID and item code โ the API validates your key, checks balance, serialises through the queue, dispatches to the fulfilment system, waits for confirmation, deducts your balance, and returns structured JSON.
ok (boolean), status (machine-readable), message (human-readable), and data (payload). Always check ok first.Request lifecycle
request
balance
lock
command
reply
balance
response
๐Authentication
Include your API key on every request as a POST field or HTTP header.
| Method | Where | Example |
|---|---|---|
| POST field | Request body | api_key=your-secret-key |
| HTTP Header | Request headers | X-API-Key: your-secret-key |
Key properties
| Property | Description |
|---|---|
| allowed_domains | Comma-separated whitelist. Requests from unlisted origins โ 403. |
| expires_at | Expiry datetime. null = never expires. |
| rate_limit | Max calls per 60-second window. 0 = unlimited. |
| balance | Shell balance. Auto-deducted on each successful top-up. |
| is_active | Admin can disable instantly. Disabled โ 403. |
| mode | product / test / disabled โ see Test vs Product Mode below. |
๐งชTest vs Product Mode
Every reseller account has one of three statuses, set by the admin. It controls which Telegram fulfilment group a request is routed to, and is recorded on every request so it can be told apart from real orders later. The two fulfilment groups are universal โ one Test group and one Product group shared by every reseller โ not configured per account.
| Mode | Behaviour |
|---|---|
| product | Live requests. Dispatched to the universal Group ID โ Product (or the global Group ID if unset). Stored with is_test = 0. Deducts SHELLS balance as normal. |
| test | Sandbox requests. Dispatched to the universal Group ID โ Test (or the global Group ID if unset). Stored with is_test = 1. Never checks or deducts SHELLS balance โ win or lose, your balance is untouched. Counts against the Test request limit instead. Use this to integrate and test your storefront without touching production fulfilment or spending SHELLS. |
| disabled | The key is rejected immediately with 403 disabled โ identical to a fully deactivated account. |
is_test is decided entirely by your account's current mode โ you never send it yourself. Every Top-Up response includes "is_test" and "mode" so your integration can confirm which one just ran.admin_resellers.php โ every reseller in Test mode shares the same Test group, and every reseller in Product mode shares the same Product group. Only the per-reseller Mode itself is set individually. The single global Group ID on the Site Settings page still works as the fallback if either universal ID is unset โ that page and behaviour are unchanged.low_balance can't happen in Test mode, and balance_before/balance_after in the response stay identical. What Test mode does reduce is your remaining daily Test request count (below) โ every Test request counts against it regardless of whether it succeeds or fails.Test request limit
Test mode also has a dynamic, admin-configurable limit on how many Test requests a reseller can send โ one number, set on admin_resellers.php, applied to every reseller in Test mode. It is always a real, positive number โ there is no "unlimited" option. Usage is a persistent running counter per reseller that does not reset on any schedule; the admin can view, adjust, or reset it anytime for any reseller.
| Field | Where | Meaning |
|---|---|---|
| test_request_limit | admin table | Universal cap on Test-mode requests per reseller. Always โฅ 1 โ the admin panel won't accept 0 or blank. Changing it takes effect immediately โ no deploy needed. |
| test_requests_used | resellers table | Per-reseller running counter. Incremented by 1 on every Test-mode request (success or failure). Never auto-resets โ admin adjusts/resets it per reseller via the pencil icon next to Test Usage on admin_resellers.php. |
Once a Test-mode reseller's usage reaches the limit, further Top-Up calls return 429 test_limit_reached until the admin raises the limit or resets that reseller's usage. Check current usage anytime with GET /api.php?whoami, which returns test_request_limit, test_requests_used, and test_requests_remaining. Every Test-mode Top-Up response โ success or failure โ also includes these three fields.
// Test-mode Top-Up once the limit is hit { "ok": false, "status": "test_limit_reached", "message": "Test request limit reached (50/50). Ask admin to raise or reset your usage on admin_resellers.php, or switch to Product mode.", "data": { "test_request_limit": 50, "test_requests_used": 50, "mode": "test" } }
Check your own current mode anytime with GET /api.php?whoami, and review past requests โ tagged Test or Product โ with GET /api.php?history. Both are read-only and never change live parameters.
โ๏ธQueue System
Only one top-up dispatches at a time, preventing fulfilment responses from being mixed up when multiple requests arrive simultaneously.
๐Top-Up
Validates balance, queues the request, dispatches to fulfilment, waits for confirmation, deducts balance, and returns the result.
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| api_key | string | REQUIRED | Reseller API key. Or use X-API-Key header. |
| player_id | string | REQUIRED | In-game player ID to top up. |
| item_code | string | REQUIRED | Item to deliver (lowercase). See Item Codes. |
| quantity | integer | OPTIONAL | Units. Default: 1. Max: 99. |
Success 200
{
"ok": true,
"status": "success",
"message": "โ
Top-up delivered successfully.",
"data": {
"queue_id": 1042,
"product": "Weekly Pass",
"shell_cost": 86,
"balance_before": 5000,
"balance_after": 4914,
"balance_deducted":true,
"shells_deducted": "86 SHELLS",
"new_balance": "4914.00 SHELLS",
"is_test": false,
"mode": "product"
}
}Same request, but in Test mode
{
"ok": true,
"status": "success",
"message": "โ
Top-up delivered successfully.",
"data": {
"queue_id": 1043,
"product": "Weekly Pass",
"shell_cost": 86,
"balance_before": 5000,
"balance_after": 5000,
"balance_deducted":false,
"is_test": true,
"mode": "test",
"test_request_limit": 50,
"test_requests_used": 13,
"test_requests_remaining": 37
}
}balance_before equals balance_after โ Test mode never touches SHELLS. test_requests_used is a running total that only changes when a Test request is sent or the admin resets it โ it does not reset on a schedule.Insufficient balance 402
{
"ok": false,
"status": "low_balance",
"message": "Insufficient balance. Required: 86 SHELLS, Available: 40 SHELLS.",
"data": {
"queue_id": 1043,
"required_shells": 86,
"available_shells":40
}
}Failed / timeout 502
{
"ok": false,
"status": "failed",
"message": "โ ๏ธ Top-up failed or timed out.",
"data": { "queue_id": 1044, "debug_msgs": ["..."] }
}๐ฆProducts
Returns the live product catalogue. No authentication required. Fetch at startup to keep pricing in sync.
{
"ok": true,
"products": [
{ "item_code": "25", "name": "25 Shells Pack", "shell_cost": "13.00" },
{ "item_code": "weekly", "name": "Weekly Pass", "shell_cost": "86.00" }
]
}๐ฉบHealth Check
Returns server health โ PHP version, DB connectivity, table existence, reseller count. No auth required. Use this to diagnose integration issues before going live.
๐Verify Player
Looks up a player's profile before placing a top-up. Requires a valid API key โ included free with all reseller accounts. The upstream verification service URL and credentials are never exposed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| api_key | string | REQUIRED | Your reseller API key. |
| uid | string | REQUIRED | In-game player UID to look up. |
| region | string | OPTIONAL | Server region code (e.g. SG, IND). Default: IND. |
Success 200
{
"ok": true,
"status": "found",
"data": {
"basicInfo": {
"accountId": "12345678",
"nickname": "FB:ใ
ค@GMRemyX",
"level": 68,
"liked": 3907634,
"headPic": 902000157,
"bannerId": 901052004,
"badgeId": 1001000097,
"badgeCnt": 14,
"exp": 2430062,
"region": "SG",
"rank": 323,
"rankingPoints": 4828,
"maxRank": 323,
"csRank": 317,
"csRankingPoints": 70,
"csMaxRank": 317,
"releaseVersion": "OB53",
"seasonId": 51,
"title": 904990070,
"weaponSkinShows": [907193507, 912053001, 914053001],
"createAt": "1512595169",
"lastLoginAt": "1780502412",
"showBrRank": true,
"showCsRank": true,
"accountType": 1,
"pinId": 910040001,
"primePrivilegeDetail": { "primeLevel": 8, "privilegeIdList": ["..."] },
"externalIconInfo": { "showType": "...", "status": "..." }
},
"captainBasicInfo": { /* same fields as basicInfo + extraField_77, extraField_78 */ },
"clanBasicInfo": {
"clanId": "60893361",
"clanName": "MแดแดแดสEแด แดTแดแดแด",
"clanLevel": 7,
"capacity": 55,
"memberNum": 32,
"captainId": "12345678"
},
"creditScoreInfo": {
"creditScore": 100,
"rewardState": "REWARD_STATE_UNCLAIMED",
"rewardEndAt": "1780279506",
"rewardStartAt":"1780279506"
},
"petInfo": {
"id": 1300000071,
"level": 7,
"exp": 6000,
"isSelected": true,
"skinId": 1310000071,
"selectedSkillId": 1315000005
},
"profileInfo": {
"avatarId": 902000157,
"clothes": [205000455, 203000156, "..."],
"equipedSkills": [16, 7606, 8, 1, "..."],
"isSelected": true,
"isSelectedAwaken": true
},
"socialInfo": {
"accountId": "12345678",
"signature": "FB : GM Remy | TikTok :gmremyx | IG GM Remy"
},
"diamondCostRes": { "diamondCost": 0 }
}
}Key fields for checkout
| Field path | Type | Use |
|---|---|---|
| data.basicInfo.nickname | string | Display to customer for confirmation |
| data.basicInfo.level | integer | Player level (1โ100) |
| data.basicInfo.headPic | integer | Avatar ID โ use to build avatar URL |
| data.basicInfo.region | string | Server region, e.g. SG |
| data.basicInfo.liked | integer | Total likes received |
| data.clanBasicInfo.clanName | string | Guild name |
| data.petInfo.id | integer | Active pet ID |
cURL example
curl "https://zankethstore.com/tg/api.php?verify&api_key=YOUR_KEY&uid=12345678®ion=SG"
PHP example
$res = json_decode(file_get_contents(
'https://zankethstore.com/tg/api.php?verify'
.'&api_key=YOUR_KEY'
.'&uid=' . urlencode($playerId)
.'®ion=SG'
), true);
if ($res['ok']) {
$name = $res['data']['basicInfo']['nickname'];
$level = $res['data']['basicInfo']['level'];
$avatar = $res['data']['basicInfo']['headPic'];
echo "Player: $name (Level $level)";
} else {
echo "Error: " . $res['message'];
}Error responses
// Invalid or missing key { "ok": false, "status": "invalid_key", "message": "Invalid API key." } { "ok": false, "status": "missing_key", "message": "api_key is required." } { "ok": false, "status": "missing_uid", "message": "uid (player_id) is required." } { "ok": false, "status": "key_expired", "message": "API key expired." } { "ok": false, "status": "upstream_error", "message": "Verification service unavailable." }
๐ชชAccount / Whoami
Returns your account's current status โ Product, Test, or Disabled โ plus balance and rate limit. Read-only: it never changes any live top-up parameters, so it's safe to call before every session to confirm which mode you're about to dispatch into.
Success 200
{
"ok": true,
"status": "found",
"data": {
"reseller": "Shop Name",
"account_mode": "test",
"is_test": true,
"active": true,
"balance": 4914,
"rate_limit": 30,
"expires_at": "2026-12-31 23:59:59",
"key_expired": false,
"test_request_limit": 50,
"test_requests_used": 12,
"test_requests_remaining": 38
}
}test_request_limit is always a real, positive number set by the admin โ it can never be unlimited. test_requests_used is a running counter that only changes when you send a Test request or the admin manually adjusts/resets it on admin_resellers.php โ it does not reset automatically.๐Request History
Returns your own past requests โ read-only, does not consume balance, touch the queue, or change any current top-up parameters. Use it to review or audit what's already been sent, filtered by Test or Product if needed.
Parameters
| Param | Type | Description | |
|---|---|---|---|
| api_key | string | REQUIRED | Your reseller API key. |
| limit | integer | OPTIONAL | Max rows to return. Default 20, max 100. |
| mode | string | OPTIONAL | test or product to filter. Omit for both. |
Success 200
{
"ok": true,
"status": "found",
"data": {
"count": 2,
"requests": [
{ "queue_id": 1042, "player_id": "123456789", "item_code": "weekly", "quantity": 1, "status": "success", "is_test": 0, "shell_cost": 86, "created_at": "2026-07-01 10:04:12" },
{ "queue_id": 1041, "player_id": "999999999", "item_code": "25", "quantity": 1, "status": "failed", "is_test": 1, "shell_cost": 13, "created_at": "2026-07-01 09:58:44" }
]
}
}๐ฎItem Codes
Pass item_code exactly as shown (lowercase). Total shell cost = shell_cost ร quantity.
Shell packs
| item_code | Name | Shell cost / unit |
|---|---|---|
| 25 | 25 Shells Pack | 13 SHELLS |
| 100 | 100 Shells Pack | 50 SHELLS |
| 310 | 310 Shells Pack | 152 SHELLS |
| 520 | 520 Shells Pack | 254 SHELLS |
| 1060 | 1,060 Shells Pack | 500 SHELLS |
| 2180 | 2,180 Shells Pack | 1,010 SHELLS |
| 5600 | 5,600 Shells Pack | 2,500 SHELLS |
| 11500 | 11,500 Shells Pack | 5,150 SHELLS |
Passes & subscriptions
| item_code | Name | Shell cost / unit |
|---|---|---|
| lite | Lite Pass | 18 SHELLS |
| weekly | Weekly Pass | 86 SHELLS |
| monthly | Monthly Pass | 430 SHELLS |
Evo passes
| item_code | Name | Shell cost / unit |
|---|---|---|
| evo3 | Evo 3-Day Pass | 30 SHELLS |
| evo7 | Evo 7-Day Pass | 45 SHELLS |
| evo30 | Evo 30-Day Pass | 135 SHELLS |
GET /api.php?products at startup to get live pricing. Admin can update prices at any time.โกError Codes
All errors return JSON with "ok": false. Use the status field for programmatic handling.
missing_playermissing_itemmissing_keyinvalid_key?checkkey=YOUR_KEY to diagnose.disabledkey_expireddomain_blockedlow_balancerequired_shells and available_shells.rate_limitedtest_limit_reachedadmin_resellers.php. Check ?whoami for current usage, or switch to Product mode. Doesn't apply to Product-mode requests.processing_errordb_errorqueue_id.faileddebug_msgs and retry.๐ก๏ธSecurity
Key Hashing
Raw keys never stored. Only SHA-256 hashes in DB.
Domain Whitelist
Each key locked to approved domains. Unknown origins โ 403.
Balance Guard
Shell balance checked before dispatch. Orders that would overdraft โ 402.
Queue Lock
Only one fulfilment runs at a time. Prevents mixed responses.
Key Expiry
Every key has an expiry date. Expired โ 403. Renew via admin panel.
Audit Log
Every call logged to api_call_log with IP, domain, status, timestamp.
โฑRate Limits
Sliding 60-second window per API key. Exceeding the limit โ 429.
| Plan | Limit | Use case |
|---|---|---|
| Standard | 30 / min | Moderate traffic |
| High-volume | 60 / min | Busy storefronts |
| Unlimited | 0 (none) | Trusted internal systems |
๐PHP
<?php $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://zankethstore.com/tg/api.php', CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_TIMEOUT => 120, CURLOPT_POSTFIELDS => http_build_query([ 'api_key' => 'your-reseller-api-key', 'player_id' => '123456789', 'item_code' => 'weekly', 'quantity' => 1, ]), ]); $res = json_decode(curl_exec($ch), true); curl_close($ch); if ($res['ok']) { echo "โ Cost: " . $res['data']['shell_cost'] . " | Balance: " . $res['data']['balance_after']; } elseif ($res['status'] === 'low_balance') { echo "โ Need: ".$res['data']['required_shells']." | Have: ".$res['data']['available_shells']; } else { echo "โ " . $res['message']; }
๐จJavaScript (Node.js)
const axios = require('axios'); async function topUp(playerId, itemCode, qty = 1) { const { data } = await axios.post( 'https://zankethstore.com/tg/api.php', new URLSearchParams({ api_key: 'your-key', player_id: playerId, item_code: itemCode, quantity: qty }).toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, timeout: 120000 } ); if (data.ok) console.log(`โ Cost: ${data.data.shell_cost} | Balance: ${data.data.balance_after}`); else if (data.status === 'low_balance') console.error(`โ Need ${data.data.required_shells}, have ${data.data.available_shells}`); else console.error(`โ ${data.message}`); return data; }
๐Python
import requests def top_up(player_id, item_code, quantity=1): data = requests.post( 'https://zankethstore.com/tg/api.php', data={ 'api_key': 'your-key', 'player_id': player_id, 'item_code': item_code, 'quantity': quantity }, timeout=120 ).json() if data['ok']: print(f"โ Cost: {data['data']['shell_cost']} | Balance: {data['data']['balance_after']}") elif data['status'] == 'low_balance': print(f"โ Need {data['data']['required_shells']}, have {data['data']['available_shells']}") else: print(f"โ {data['message']}") return data
๐ฅcURL
# Top-up curl -X POST https://zankethstore.com/tg/api.php \ --max-time 120 \ -d "api_key=your-key" \ -d "player_id=123456789" \ -d "item_code=weekly" \ -d "quantity=1" # Verify player curl "https://zankethstore.com/tg/api.php?verify&api_key=your-key&uid=123456789®ion=SG" # Live product list curl https://zankethstore.com/tg/api.php?products # Health check curl https://zankethstore.com/tg/api.php?test # Diagnose key curl https://zankethstore.com/tg/api.php?checkkey=your-raw-key
โ๏ธKey Management
Create and manage keys from the Admin Panel at /admin.php or via the CLI script. Per-reseller Test/Product/Disable mode and the two Telegram Group IDs are managed separately on /admin_resellers.php โ the global Site Settings page (admin_variables.php) is unaffected.
# List resellers php reseller_admin.php list # Create (prints key ONCE โ save immediately) php reseller_admin.php add "Shop Name" "shop.com" 365 60 # Disable / enable php reseller_admin.php revoke 3 php reseller_admin.php enable 3 # History & stats php reseller_admin.php history 3 php reseller_admin.php stats
/admin_resellers.php to set its Mode (Product / Test / Disable). The Group ID โ Test and Group ID โ Product fields on that same page are universal and apply to every reseller; you only set them once, not per account.๐๏ธDatabase
Run api_schema.sql once to create all tables. Safe to re-run.
resellers
| Column | Type | Notes |
|---|---|---|
| api_key | VARCHAR(64) | SHA-256 hash of raw key |
| balance | DECIMAL(10,2) | Auto-deducted on success. Top up via admin. |
| allowed_domains | TEXT | Comma-separated whitelist |
| rate_limit | SMALLINT | Calls/min. 0 = unlimited |
| mode | ENUM('product','test','disabled') | 3-way status. See Test vs Product Mode. Managed on admin_resellers.php. |
| test_requests_used | INT | Per-reseller running counter checked against the universal test_request_limit. +1 on every Test-mode request. Never auto-resets โ admin adjusts/resets per reseller on admin_resellers.php. |
admin
| Column | Type | Notes |
|---|---|---|
| group_id | BIGINT | Original single Group ID. Managed on admin_variables.php (unchanged). Used as the fallback below. |
| group_id_test | BIGINT NULL | Universal Telegram group used for every reseller when mode=test. Falls back to group_id if NULL. Managed on admin_resellers.php. |
| group_id_product | BIGINT NULL | Universal Telegram group used for every reseller when mode=product. Falls back to group_id if NULL. Managed on admin_resellers.php. |
| test_request_limit | INT | Universal cap on Test-mode requests per reseller, checked against each reseller's test_requests_used. Always โฅ 1 โ never unlimited. Dynamic โ takes effect immediately. Managed on admin_resellers.php. |
products
| Column | Type | Notes |
|---|---|---|
| item_code | VARCHAR(60) | Unique, lowercase. Matches API item_code |
| shell_cost | DECIMAL(10,2) | Cost per unit checked against reseller balance |
| is_active | TINYINT(1) | Inactive items โ missing_item error |
api_queue
| Column | Notes |
|---|---|
| id | Returned as queue_id in all responses |
| reseller_id | NULL for internal orders (manual/wallet/instant) |
| status | pending โ processing โ success | failed | timeout |
| origin_domain | manual / instant / wallet / reseller domain |
| is_test | Set automatically from the reseller's mode at request time. 1 = Test, 0 = Product. |
api_call_log
| Column | Notes |
|---|---|
| is_test | Same flag as api_queue.is_test, mirrored onto every logged call. |
mode/test_requests_used on resellers; group_id_test/group_id_product/test_request_limit on admin; is_test on api_queue/api_call_log) are added automatically the first time api.php or admin_resellers.php runs โ no manual migration needed.