{"openapi":"3.1.0","info":{"title":"Zad Top API","description":"\nHTTP API behind **[@ZadTopBot](https://t.me/ZadTopBot)** — the same engine, wallet, stock, request\nallowance and history as the Telegram bot.\n\n**Auth** — send `X-API-Key: pk_…` on every route below. Keys are created in the bot under\n*Subscription → HTTP API → API key*, and need an active plan plus the API add-on (or an admin trial).\n\n**Async redeem** — `POST /v1/jobs/instant-redeem` or `/v1/jobs/stock-redeem` returns\n`{\"job_id\": \"...\", \"status\": \"pending\"}`. Poll `GET /v1/jobs/{job_id}?wait=25` (up to 60s per call).\n`done` is the queue state, not the business result: check `result.ok_count` and each\n`result.results[].success` / `err_code`.\n\n**Billing** — 1 request per code, charged when the worker runs. Player lookup costs 0.25, and only\nwhen it succeeds. Free-trial requests are spent before the daily plan allowance, which resets on the\nUTC day.\n\n**Check before you redeem** — `POST /v1/codes/check` reads whether a card is unused, already used, or\nnever existed, *without* spending it, and a good card stays good however often you ask.\n`POST /v1/jobs/code-check` does the same for a bulk batch. Every redeem also checks its own cards\nfirst and reports a dead one without sending it, so a used code never eats a redeem attempt.\n\n**A valid card is credited on contact.** The shop credits a good voucher the moment `pay/init` sees\nit, so send each code to a redeem route exactly once. The check route is the dry run; the redeem\nroute is not.\n\n**Region** — players from almost every country are supported, not only the Middle East. Where Garena\nsells no vouchers at all (the United States, Argentina, Chile), `GET /v1/player/lookup` answers\n`422 UNSUPPORTED_REGION` before any card is at risk.\n\n**Restarts** — during a safe restart new jobs answer `503 SERVICE_DRAINING`; jobs already running are\nfinished first. Retry shortly.\n\nFull reference with copy-paste samples in cURL, Python, JavaScript, PHP and Go: [`/docs`](/docs).\n","termsOfService":"https://www.zadtop.com/terms.html","contact":{"name":"Zad Top support","url":"https://t.me/ZadTop_support"},"version":"1.4.0"},"paths":{"/health":{"get":{"tags":["Service"],"summary":"Liveness probe (no API key)","description":"Answers `{\"ok\": true}` as long as the process serves traffic. Safe for uptime monitors.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"ok":true}}}}}}},"/v1/me":{"get":{"tags":["Account"],"summary":"Who this key belongs to","description":"Wallet balance, the plan behind the key, today's usage, and whether API access is active.","operationId":"me_v1_me_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"chat_id":123456789,"balance_usdt":42.5,"subscription":{"plan_key":"p2","daily_limit":200,"usage_today":17,"trial_remaining":0,"plans":[{"plan_key":"p2","games":["freefire","pubg"],"daily_limit":200,"ends_at":1790000000}]},"has_api_subscription":true}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/quota":{"get":{"tags":["Account"],"summary":"Requests left right now","description":"Free-trial requests are spent first, then the combined daily allowance of active plans (reset on the UTC day), then an admin API trial if there is one. `total_requests_left_approx` is what you can still spend today.\n\nWith `game`, the plan part counts only plans that cover that game.","operationId":"quota_v1_quota_get","parameters":[{"name":"game","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"freefire | pubg | ludo | ludogold | jawaker","title":"Game"},"description":"freefire | pubg | ludo | ludogold | jawaker"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"trial_remaining":0,"daily_limit_combined":200,"usage_today":17,"daily_left_subscription":183,"api_trial_remaining":0,"total_requests_left_approx":183}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/player/lookup":{"get":{"tags":["Catalog"],"summary":"Resolve a player id to its in-game nickname","description":"Free Fire only. Use it on a checkout screen so the buyer confirms the id before any card is spent.\n\nCosts **0.25 requests**, charged only on success. The player is remembered under `/v1/players`.","operationId":"player_lookup_v1_player_lookup_get","parameters":[{"name":"player_id","in":"query","required":true,"schema":{"type":"string","minLength":6,"maxLength":16,"description":"Digits only. Free Fire 6–12; PUBG 8–11 starting with 5; Yalla Ludo 6–16; Jawaker 6–12.","title":"Player Id"},"description":"Digits only. Free Fire 6–12; PUBG 8–11 starting with 5; Yalla Ludo 6–16; Jawaker 6–12."},{"name":"game","in":"query","required":false,"schema":{"type":"string","description":"freefire | pubg | ludo | ludogold | jawaker","default":"freefire","title":"Game"},"description":"freefire | pubg | ludo | ludogold | jawaker"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"ok":true,"player_id":"123456789","player_name":"ZadTopPlayer","region":"ME","quota_requests_charged":0.25}}}},"400":{"description":"INVALID_PLAYER_ID · UNKNOWN_GAME · GAME_LOOKUP_UNAVAILABLE"},"403":{"description":"GAME_NOT_IN_PLAN — none of your plans covers this game"},"404":{"description":"PLAYER_NOT_FOUND — no account with that id"},"422":{"description":"UNSUPPORTED_REGION — the account exists, but Garena sells no vouchers in its country, so no card can be redeemed onto it; `region` and `player_name` are returned so you can tell the buyer"},"429":{"description":"RATE_LIMIT — the shop lane for this key is busy · QUOTA_EXHAUSTED — fewer requests left than this call costs; nothing was done"},"502":{"description":"LOOKUP_FAILED — shop unreachable; nothing charged"}},"security":[{"ApiKeyAuth":[]}]}},"/v1/codes/check":{"post":{"tags":["Catalog"],"summary":"Read whether codes are unused, already used, or were never real","description":"The storefront has a read-only endpoint for cards, so this **does not redeem anything** — a good code is still good afterwards, and may be checked as often as you like.\n\nSynchronous, up to **20** codes; for larger batches use `POST /v1/jobs/code-check`, which takes up to 10000 and is polled like a redeem job.\n\n`status` is one of `valid` · `used` · `invalid` · `expired` · `inactive` · `blocked` · `region_mismatch` · `unknown` · `error`. Only `valid` means the card can be redeemed; `unknown` and `error` mean we could not find out, so treat them as *not yet known* rather than bad.\n\nBilling: **1.0 request per card read**, the same as a redeem — a card the shop never answered for is not charged. `with_value` adds the face value (`shell_amount`) and the pack it credits (`amount`), at one extra shop call per card; it is quoted the same for a used card, so never read value as status.","operationId":"codes_check_v1_codes_check_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CodeCheckBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"ok":true,"checked":3,"counts":{"valid":1,"used":1,"invalid":1},"quota_requests_charged":0.3,"results":[{"code":"7397062240255931","status":"valid","redeemable":true,"shell_amount":50,"amount":100,"bonus":0},{"code":"5539151276341494","status":"used","redeemable":false,"error":"error_used_card","shell_amount":50,"amount":100,"bonus":0},{"code":"0000000000000000","status":"invalid","redeemable":false,"error":"error_invalid_card"}]}}}},"400":{"description":"INVALID_CODE · TOO_MANY_CODES · UNKNOWN_GAME · GAME_REDEEM_UNAVAILABLE"},"403":{"description":"GAME_NOT_IN_PLAN — none of your plans covers this game"},"429":{"description":"RATE_LIMIT — the shop lane for this key is busy · QUOTA_EXHAUSTED — the batch costs more than you have left; nothing was read"},"503":{"description":"SERVICE_DRAINING — safe restart in progress"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/stock/summary":{"get":{"tags":["Catalog"],"summary":"Vouchers you have stored, per pack","description":"Counts only cards that are available — reserved, used and failed ones are excluded. Read this before `/v1/jobs/stock-redeem` so `picks` cannot ask for more than you hold.","operationId":"stock_summary_v1_stock_summary_get","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"freefire":{"name":"Free Fire","redeemable":true,"by_denomination":{"100":12,"210":4,"530":0,"1080":2,"2200":0},"total":18},"ludo":{"name":"Yalla Ludo Diamonds","redeemable":true,"by_denomination":{"830":5},"total":5},"ludogold":{"name":"Yalla Ludo Gold","redeemable":true,"by_denomination":{"68500":2},"total":2},"pubg":{"name":"PUBG Mobile","redeemable":true,"by_denomination":{"60":8,"325":1},"total":9}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/history":{"get":{"tags":["Account"],"summary":"Redeem history, one row per code","description":"Newest first, covering both bot and API redeems. The same filters as the Telegram history panel: `player_id` and `code` match on substrings, `days` accepts 7, 30 or 90.\n\nKeep `history_id` to draw the order card later with `POST /v1/order/screenshot`.","operationId":"history_v1_history_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"player_id","in":"query","required":false,"schema":{"type":"string","maxLength":32,"description":"Substring match on player id","default":"","title":"Player Id"},"description":"Substring match on player id"},{"name":"code","in":"query","required":false,"schema":{"type":"string","maxLength":32,"description":"Substring match on voucher code","default":"","title":"Code"},"description":"Substring match on voucher code"},{"name":"days","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"7, 30, or 90. Omit for all time.","title":"Days"},"description":"7, 30, or 90. Omit for all time."},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"items":[{"id":"67ff1a2b3c4d5e6f70819277","history_id":"67ff1a2b3c4d5e6f70819270","player_id":"123456789","nickname":"ZadTopPlayer","game":"freefire","code":"4233939008625064","status":"ok","outcome":"ok","amount":100,"bonus":10,"total":110,"display_id":"FF2409091234567","source":"api","point_name":"Diamonds","time_created":"2026-09-12 10:31:04","time_stamp":1789123864}],"limit":20,"offset":0,"total":1,"filters":{"player_id":"","code":""}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/players":{"get":{"tags":["Account"],"summary":"Players seen on this account","description":"Every player id this account looked up or redeemed to, newest first — a ready-made customer list for a shop front end. Written by both the bot and the API.","operationId":"saved_players_v1_players_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"items":[{"player_id":"123456789","nickname":"ZadTopPlayer","game":"freefire","region":"ME","last_seen_stamp":1789123864}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/subscription/purchase":{"post":{"tags":["Billing"],"summary":"Buy a subscription plan from the wallet","description":"Charges the USDT balance and raises the daily request allowance for 30 days. `games` picks what the plan covers (omitted = all games): one game is the base price, two ×1.3, all ×1.5, and the daily limit is shared by them. Buying a plan you already hold for the same games extends it.","operationId":"purchase_v1_subscription_purchase_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseBody"}}}},"responses":{"200":{"description":"Plan active","content":{"application/json":{"schema":{}}}},"400":{"description":"INSUFFICIENT_BALANCE · UNKNOWN_GAME · unknown plan_key"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/subscription/purchase-api-addon":{"post":{"tags":["Billing"],"summary":"Buy or extend the HTTP API add-on","description":"Adds 30 days of API access on top of an active plan. Without a plan the call returns `NEED_PLAN`, and existing keys stop working when no plan is active.","operationId":"purchase_api_addon_v1_subscription_purchase_api_addon_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Add-on active until the returned date","content":{"application/json":{"schema":{}}}},"400":{"description":"NEED_PLAN · INSUFFICIENT_BALANCE"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/jobs/instant-redeem":{"post":{"tags":["Jobs"],"summary":"Queue an instant redeem of codes you send in the request","description":"Creates an async job that redeems every code in `codes` onto `player_id`.\n\nReturns `202`-style payload `{job_id, status:\"pending\"}` immediately; read the outcome with `GET /v1/jobs/{job_id}?wait=25`.\n\nBilling: **1 request per code**, charged when the worker runs.\n\nA card is judged only by redeeming it, so a good code is credited on first contact — send a code here exactly once.","operationId":"instant_redeem_v1_jobs_instant_redeem_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstantRedeemBody"}}}},"responses":{"200":{"description":"Job queued","content":{"application/json":{"schema":{},"example":{"job_id":"67ff1a2b3c4d5e6f70819200","status":"pending"}}}},"400":{"description":"INVALID_PLAYER_ID · INVALID_CODE · UNKNOWN_GAME · GAME_REDEEM_UNAVAILABLE · MISSING_TIER"},"403":{"description":"GAME_NOT_IN_PLAN — none of your plans covers this game"},"503":{"description":"SERVICE_DRAINING — safe restart in progress"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/jobs/code-check":{"post":{"tags":["Jobs"],"summary":"Queue a bulk read of many codes, without redeeming any","description":"The batch form of `POST /v1/codes/check`: up to **10000** cards go down one shop session, which takes minutes rather than seconds — hence a job.\n\nReturns `{job_id, status:\"pending\"}`; read the outcome with `GET /v1/jobs/{job_id}?wait=25`. The result carries `counts` and one row per card in the same shape as the synchronous route.\n\nBilling: **1.0 request per card read**, the same as a redeem, charged when the worker runs. Nothing is redeemed and no card is consumed, whatever the verdict.","operationId":"bulk_code_check_v1_jobs_code_check_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCodeCheckBody"}}}},"responses":{"200":{"description":"Job queued","content":{"application/json":{"schema":{},"example":{"job_id":"67ff1a2b3c4d5e6f70819202","status":"pending"}}}},"400":{"description":"INVALID_CODE · TOO_MANY_CODES · GAME_REDEEM_UNAVAILABLE"},"403":{"description":"GAME_NOT_IN_PLAN — none of your plans covers this game"},"503":{"description":"SERVICE_DRAINING — safe restart in progress"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/jobs/stock-redeem":{"post":{"tags":["Jobs"],"summary":"Queue a redeem from your stored vouchers","description":"Picks cards out of your own stock by pack size and redeems them onto `player_id`. The chosen cards are reserved before the job runs, so a parallel job cannot take them.\n\nBilling: **1 request per card** reserved. A card refused for a reason that is not the card's fault (network, captcha, rate limit) goes back to stock.","operationId":"stock_redeem_v1_jobs_stock_redeem_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StockRedeemBody"}}}},"responses":{"200":{"description":"Job queued","content":{"application/json":{"schema":{},"example":{"job_id":"67ff1a2b3c4d5e6f70819201","status":"pending"}}}},"400":{"description":"INVALID_PLAYER_ID · MISSING_PICKS · GAME_REDEEM_UNAVAILABLE"},"403":{"description":"GAME_NOT_IN_PLAN — none of your plans covers this game"},"503":{"description":"SERVICE_DRAINING — safe restart in progress"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/jobs/{job_id}":{"get":{"tags":["Jobs"],"summary":"Read a job, optionally waiting for it to finish","description":"`wait=25` holds the connection until the job leaves `pending`/`running` (60s ceiling), which is cheaper than a polling loop.\n\n`status: \"done\"` is the queue result. The business result is per code: `result.ok_count`, `result.failed_count`, and `result.results[].success` with `err_code` for each refusal. `result.history_id` is the receipt handle.","operationId":"get_job_v1_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"wait","in":"query","required":false,"schema":{"type":"number","maximum":60,"minimum":0,"description":"Seconds to wait for a terminal state (max 60)","default":0,"title":"Wait"},"description":"Seconds to wait for a terminal state (max 60)"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"id":"67ff1a2b3c4d5e6f70819200","type":"instant_redeem","status":"done","result":{"game":"freefire","player_id":"123456789","success":false,"ok_count":1,"failed_count":1,"credited":110,"point_name":"Diamonds","nickname":"ZadTopPlayer","history_id":"67ff1a2b3c4d5e6f70819270","results":[{"ok":true,"success":true,"code":"4233939008625064","player_id":"123456789","nickname":"ZadTopPlayer","display_id":"FF2409091234567","amount":100,"bonus":10,"total":110,"point_name":"Diamonds","outcome":"ok"},{"ok":false,"success":false,"code":"4233939008625065","player_id":"123456789","err_code":"CODE_ALREADY_USED","outcome":"used_card"}]},"created_at_stamp":1789123840,"finished_at_stamp":1789123864}}}},"404":{"description":"Job not found for this key"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/jobs":{"get":{"tags":["Jobs"],"summary":"List your recent jobs","description":"Newest first, same sanitized shape as `GET /v1/jobs/{job_id}`. Useful to rebuild state after a crash.","operationId":"list_jobs_v1_jobs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"jobs":[{"id":"67ff1a2b3c4d5e6f70819200","type":"instant_redeem","status":"done","created_at_stamp":1789123840,"finished_at_stamp":1789123864}],"limit":20,"offset":0,"total":1}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/order/screenshot":{"post":{"tags":["Receipts"],"summary":"Render the order card of a successful redeem","description":"Draws the same receipt image the bot sends, from data already stored on the server, and returns **raw PNG bytes** — not JSON.\n\nAddress the row either by `job_id` (an API job you own) or by `history_id` (any redeem of yours, including ones made inside Telegram). `result_index` picks the row in a batch and counts successful rows only when you pass `history_id`.\n\nThe time on the card is drawn in the time zone chosen in the bot (My account → Time zone); accounts that never picked one get the shop's own region.\n\nFree of quota, but limited per key per minute.","operationId":"order_screenshot_api_v1_order_screenshot_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenshotBody"}}}},"responses":{"200":{"description":"PNG image","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"MISSING_JOB_OR_HISTORY_ID · NO_ORDER_DETAILS · JOB_NOT_SUCCESSFUL"},"404":{"description":"JOB_NOT_FOUND · HISTORY_NOT_FOUND"},"409":{"description":"JOB_NOT_READY — still pending or running"},"429":{"description":"SCREENSHOT_RATE_LIMIT — retry after 60s"},"500":{"description":"ORDER_SCREENSHOT_FAILED"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/order/screenshot":{"post":{"tags":["Receipts"],"summary":"Render the order card of a successful redeem","description":"Draws the same receipt image the bot sends, from data already stored on the server, and returns **raw PNG bytes** — not JSON.\n\nAddress the row either by `job_id` (an API job you own) or by `history_id` (any redeem of yours, including ones made inside Telegram). `result_index` picks the row in a batch and counts successful rows only when you pass `history_id`.\n\nThe time on the card is drawn in the time zone chosen in the bot (My account → Time zone); accounts that never picked one get the shop's own region.\n\nFree of quota, but limited per key per minute.","operationId":"order_screenshot_v1_order_screenshot_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenshotBody"}}}},"responses":{"200":{"description":"PNG image","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"MISSING_JOB_OR_HISTORY_ID · NO_ORDER_DETAILS · JOB_NOT_SUCCESSFUL"},"404":{"description":"JOB_NOT_FOUND · HISTORY_NOT_FOUND"},"409":{"description":"JOB_NOT_READY — still pending or running"},"429":{"description":"SCREENSHOT_RATE_LIMIT — retry after 60s"},"500":{"description":"ORDER_SCREENSHOT_FAILED"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}}},"components":{"schemas":{"BulkCodeCheckBody":{"properties":{"codes":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Codes","description":"Free Fire (16 digits) or PUBG (18 letters/digits) codes, up to 10000 per job. Duplicates are collapsed. Nothing is redeemed."},"game":{"type":"string","title":"Game","description":"freefire | pubg","default":"freefire"},"with_value":{"type":"boolean","title":"With Value","description":"Price every card as well. Off by default for bulk: it doubles the shop calls. Each card is quoted on its own — a batch may mix tiers.","default":false}},"type":"object","required":["codes"],"title":"BulkCodeCheckBody","example":{"codes":["7397062240255931","0305768925042495","5539151276341494"],"game":"freefire","with_value":false}},"CodeCheckBody":{"properties":{"codes":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Codes","description":"Codes for the chosen checkable game. Spaces and dashes are stripped. Free Fire: 16 digits. PUBG: 18 letters/digits. Yalla Ludo and Jawaker cannot be checked. Reading a card does not spend it."},"game":{"type":"string","title":"Game","description":"freefire | pubg","default":"freefire"},"with_value":{"type":"boolean","title":"With Value","description":"Also price the card (one extra shop call per code)","default":true}},"type":"object","required":["codes"],"title":"CodeCheckBody","example":{"codes":["7397062240255931","5539151276341494","0000000000000000"],"game":"freefire","with_value":true}},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InstantRedeemBody":{"properties":{"player_id":{"type":"string","title":"Player Id","description":"Player id: Free Fire 6–12 digits; PUBG 8–11 starting with 5; Yalla Ludo 6–16; Jawaker 6–12."},"codes":{"items":{"type":"string"},"type":"array","maxItems":10,"minItems":1,"title":"Codes","description":"Codes for the chosen game, up to 10 per job. Spaces and dashes are stripped. Free Fire: 16 digits. PUBG: 18 letters/digits. Yalla Ludo: 12 letters/digits. Jawaker: 10 or 12 letters/digits. A valid card is credited the moment it is submitted, so send each code once."},"game":{"type":"string","title":"Game","description":"freefire | pubg | ludo | ludogold | jawaker","default":"freefire"},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Yalla Ludo only: the pack every code in this call is for, as an in-game quantity (e.g. 830, 68500) or a USD price (e.g. 2). A bare USD price means Diamonds; Gold must be given as its quantity. Ignored for Free Fire, PUBG and Jawaker."}},"type":"object","required":["player_id","codes"],"title":"InstantRedeemBody","example":{"codes":["4233939008625064","4233939008625065"],"game":"freefire","player_id":"123456789"}},"PurchaseBody":{"properties":{"plan_key":{"type":"string","title":"Plan Key","description":"p1 … p6 — see the Subscription menu in the bot for prices"},"games":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Games","description":"Games the plan covers: freefire | pubg | ludo | jawaker, or [\"all\"]. Omitted = all games. One game is the base price, two ×1.3, all ×1.5; the daily limit is shared by the games picked."}},"type":"object","required":["plan_key"],"title":"PurchaseBody","example":{"games":["freefire","pubg"],"plan_key":"p2"}},"ScreenshotBody":{"properties":{"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id","description":"Finished redeem job id — one of job_id / history_id is required"},"history_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"History Id","description":"redemption_history id from Telegram or /v1/history"},"result_index":{"type":"integer","minimum":0.0,"title":"Result Index","description":"Which row of a batch to draw (0-based)","default":0},"lang":{"type":"string","title":"Lang","description":"Receipt language: en or ar","default":"en"}},"type":"object","title":"ScreenshotBody","example":{"history_id":"67ff1a2b3c4d5e6f70819270","lang":"en","result_index":0}},"StockRedeemBody":{"properties":{"player_id":{"type":"string","title":"Player Id","description":"Player id for the chosen game (same rules as instant-redeem)."},"picks":{"additionalProperties":{"type":"integer"},"type":"object","title":"Picks","description":"How many cards of each pack to pull from your stock. Free Fire: 100, 210, 530, 1080, 2200. PUBG UC: 60, 325, 660, 1800, 3850, 8100. Yalla Ludo Diamonds/Gold: the quantities listed on /v1/stock/summary."},"game":{"type":"string","title":"Game","description":"freefire | pubg | ludo | ludogold | jawaker","default":"freefire"}},"type":"object","required":["player_id","picks"],"title":"StockRedeemBody","example":{"game":"freefire","picks":{"100":2,"530":1},"player_id":"123456789"}},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"tags":[{"name":"Service","description":"Public probes. No API key, no quota."},{"name":"Account","description":"Balance, subscription, request allowance, saved players, redeem history."},{"name":"Catalog","description":"Player lookup and voucher stock held for this account."},{"name":"Jobs","description":"Redeeming talks to the shop and takes seconds, so it runs as a queued job. `POST` returns a `job_id`, then `GET /v1/jobs/{job_id}?wait=25` answers the moment the job ends. `status: \"done\"` only means the worker finished — read every row in `result.results[]`."},{"name":"Receipts","description":"The shop's own order card, drawn server-side as PNG."},{"name":"Billing","description":"Buy a plan or the HTTP API add-on from the wallet balance."}],"servers":[{"url":"https://api.zadtop.com","description":"Production"}]}