Join Community Join Channel Telegram Contact Owner
King Zee Social Hub Menu
Home Boost Accounts NEW Marketplace Tools Games Buy Numbers Giveaways Groups Direct Messages 🆘 Support
Login Get Started
Developers

King Zee API Documentation

Connect your own scripts and apps to your King Zee Social Hub account

Getting Started

Every King Zee Social Hub user can generate a personal API Key and API Secret from Settings API Access. These two values authenticate every request you make to the API — treat them like a password. Your secret is shown once at generation time and never again, so save it somewhere safe immediately.

All endpoints are scoped to your own account only — you can check your own balance, list available items, view your own purchase history, and buy items on your own behalf. You cannot access any other user's data.

Jump to a section

Everything below is generated from the endpoints this server actually runs — Boost, Buy Number Server 1, Buy Number Server 2 and the Marketplace.

Live API tester — confirm it works with your own key

Paste your key + secret and this page calls the real endpoints on this server, read-only. Nothing is bought and your wallet is never charged — it only runs the browse/status calls for Boost, Server 1 numbers, Server 2 numbers and the Marketplace so you can see exactly which ones answer.

Authentication

Every request must include these two headers:

X-API-Key: your_api_key X-API-Secret: your_api_secret

Requests missing either header, or with an invalid/revoked key, get a 401 Unauthorized response.

Base URL

https://your-site.example.com/api/v1

Endpoints

MethodEndpointWhat it does
GET/meYour account info (name, email, balance, Game ID)
GET/balanceYour current wallet balance
GET/purchasesYour full purchase history
GET/purchases/:purchaseIdRe-fetch one specific old purchase's full details (account credentials/download link) by its purchase ID
GET/listingsAll available logs/tools (add ?type=tool or ?type=log to filter)
GET/listings/:idDetails of one specific listing — includes subAccounts array (with _id, label, price, sold) when it's a multi-account folder listing
POST/buy/:idPurchase a listing using your wallet balance. For folder listings, optionally pass { "subAccountId": "..." } to pick a specific account — omit it and the cheapest available one is bought automatically
POST/buy-multi/:idBuy several accounts from the same folder listing at once — body: { "subAccountIds": ["...", "..."] }. All-or-nothing: if any account was already sold, or your balance can't cover the total, nothing is charged
GET/numbers/optionsProviders/countries currently available to rent a number for, with price
POST/buy-numberRent a number — body: provider, country
GET/get-smsPoll for the OTP — query: order_id
POST/cancel-numberCancel before a code arrives and get refunded — body: order_id

Example: Check your balance

curl https://your-site.example.com/api/v1/balance \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret"

Example: List available items

curl "https://your-site.example.com/api/v1/listings?type=tool" \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret"

Example: Buy an item

No platform fee — you're charged exactly the item's listed price via the API, same as buying it through the marketplace. The response includes itemPrice and totalCharged (always equal) so you can confirm this.
curl -X POST https://your-site.example.com/api/v1/buy/LISTING_ID_HERE \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret"

Example: Buying from a folder listing (multiple accounts under one item)

Some listings are "folders" containing several individually-priced accounts (e.g. "Twitter Logs Batch" with 20 accounts inside). Check listingType === "folder" and the subAccounts array from GET /listings/:id first to see what's available and each one's price.
# Step 1 — see what's inside the folder and each account's price curl https://your-site.example.com/api/v1/listings/FOLDER_ID_HERE \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" # Step 2a — buy ONE specific account from it curl -X POST https://your-site.example.com/api/v1/buy/FOLDER_ID_HERE \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" \ -H "Content-Type: application/json" \ -d '{"subAccountId":"SUB_ACCOUNT_ID_HERE"}' # Step 2b — or buy SEVERAL accounts from it in one call curl -X POST https://your-site.example.com/api/v1/buy-multi/FOLDER_ID_HERE \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" \ -H "Content-Type: application/json" \ -d '{"subAccountIds":["SUB_ID_1","SUB_ID_2","SUB_ID_3"]}'

Example: Getting a past purchase's details again

Lost the account details from an old purchase, or need to look them up again later? Every successful /buy, /buy-multi, or on-site purchase returns a purchaseId — save it, then fetch that exact purchase any time with GET /purchases/:purchaseId.
curl https://your-site.example.com/api/v1/purchases/PURCHASE_ID_HERE \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret"

Example: Buy a Number

Numbers are used to receive a one-time verification code from the provider you choose (WhatsApp, Telegram, etc). Prices here are separate from the site's own Buy Numbers page — check /numbers/options for what's currently available and its price. Want to see this exact flow (browse buy poll done) built into a full page? /buy-number on this site is that reference implementation — same four calls below, wired to a UI.
# 1. See what's available curl https://your-site.example.com/api/v1/numbers/options \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" # 2. Rent a number curl -X POST https://your-site.example.com/api/v1/buy-number \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" \ -H "Content-Type: application/json" \ -d '{"provider":"WhatsApp","country":"United States"}' # 3. Poll for the code (repeat every few seconds until status is "received") curl "https://your-site.example.com/api/v1/get-sms?order_id=ORDER_ID_HERE" \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" # 4. If no code arrives, cancel for a refund curl -X POST https://your-site.example.com/api/v1/cancel-number \ -H "X-API-Key: your_api_key" \ -H "X-API-Secret: your_api_secret" \ -H "Content-Type: application/json" \ -d '{"order_id":"ORDER_ID_HERE"}'

Buy Number — Server 1 (curated pool)

Server 1 is the hand-picked pool: a short list of providers (WhatsApp, Telegram, …) and countries the admin has priced and enabled. It is the fastest path — one call to list options, one to rent, then poll for the code.

There are two equivalent ways in:

  • Developer API (recommended)/api/v1/* with your X-API-Key + X-API-Secret.
  • Session endpoints/api/numbers/*, used by the site's own /buy-number page; these need a signed-in session cookie/token instead of an API key.

Developer API (API key)

MethodEndpointInputReturns
GET/api/v1/numbers/optionsEnabled providers + countries with your price each
POST/api/v1/buy-number{ provider, country }{ order_id, number, price } — wallet is debited here
GET/api/v1/get-smsorder_id (query){ status: "waiting" | "received" | "cancelled", sms }
POST/api/v1/cancel-number{ order_id }Refunds you if no code has arrived yet

Session endpoints (same pool, signed-in user)

MethodEndpointInputReturns
GET/api/numbers/serversWhich servers are switched on right now: { server1: { enabled }, server2: { enabled } }. Call this first and hide the ones that are off.
GET/api/numbers/optionsPriced provider/country list for Server 1
GET/api/numbers/live-servicescountry (optional)Live services with stock and price
GET/api/numbers/live-countriesCountries currently holding stock
POST/api/numbers/buy{ provider, country }Rents the number and debits the wallet
GET/api/numbers/status/:orderIdPoll for the OTP for one order
POST/api/numbers/cancel/:orderIdCancel + refund while no code has arrived
GET/api/numbers/my-orderslimit (optional)Your recent number orders
GET/api/numbers/my-orders/searchqSearch your own orders by number or order id
GET/api/numbers/healthUpstream provider reachability — handy for a status page

Full flow (Server 1, developer API)

# 1. What can I rent, and for how much? curl "$BASE/api/v1/numbers/options" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" # 2. Rent one (wallet is charged here) curl -X POST "$BASE/api/v1/buy-number" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" \ -H "Content-Type: application/json" \ -d '{"provider":"WhatsApp","country":"United States"}' # 3. Poll every ~5s until status is "received" curl "$BASE/api/v1/get-sms?order_id=ORDER_ID" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" # 4. Nothing arrived? Cancel and get refunded curl -X POST "$BASE/api/v1/cancel-number" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" \ -H "Content-Type: application/json" \ -d '{"order_id":"ORDER_ID"}'

Server 1 errors and how to fix them

CodeMessageFix
400Server 1 is temporarily switched offAn admin disabled Server 1. Check /api/numbers/servers and use Server 2 meanwhile.
400provider and country are requiredSend both, spelled exactly as returned by /numbers/options. Never hand-type them.
400Insufficient balanceTop up. The charge is the price field from /numbers/options.
400Out of stock for that provider/countryRe-read /numbers/options (or /api/numbers/live-services) and pick another. Nothing was charged.
401UnauthorizedMissing/revoked X-API-Key + X-API-Secret, or you called a /api/numbers/* session endpoint without being signed in.
404Order not foundUse the order_id exactly as returned by the buy call — it belongs to your account only.
502Provider unreachableUpstream hiccup. Retry the same call after a few seconds; nothing was charged.

Server 2 Numbers API (all services & countries)

Server 2 is the large pool — hundreds of services and countries, live stock and live prices. You always call it in the same order: service → country → provider (price pool) → buy → poll. These four endpoints are session endpoints on /api/numbers/server2/*; the browse calls need no auth, the buy call charges your wallet and needs you signed in.
MethodEndpointQuery / BodyReturns
GET /api/numbers/server2/services search (optional) Array of { code, name, emoji, popular }, most popular first
GET /api/numbers/server2/countries service (required — the code from above) Array of { id, name, flag, count, price } — only countries with stock, cheapest first
GET /api/numbers/server2/providers service, country (both required) Array of price pools { label, maxPrice, price, count, flag }, cheapest first
GET /api/numbers/server2/operators service, country Mobile operators available for that pair — pass nothing and any operator is used
POST /api/numbers/server2/buy { service, country, maxPrice } The rented number + order id. Stock and price are re-checked live before your wallet is touched

Full flow

# 1. Find the service code (e.g. search for WhatsApp) curl "https://your-site.example.com/api/numbers/server2/services?search=whatsapp" # 2. Countries that have stock for that service curl "https://your-site.example.com/api/numbers/server2/countries?service=wa" # 3. Price pools ("providers") for that service + country curl "https://your-site.example.com/api/numbers/server2/providers?service=wa&country=187" # 4. Buy — maxPrice MUST be the pool's maxPrice value, copied exactly curl -X POST https://your-site.example.com/api/numbers/server2/buy \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_SESSION_TOKEN" \ -d '{"service":"wa","country":"187","maxPrice":0.42}'

Server 2 errors and how to fix them

StatusMessage you'll seeFix
400Server 2 is temporarily switched offAn admin disabled Server 2 in the admin panel. Use Server 1, or wait until it's switched back on — retrying won't help.
400service is required / service and country are requiredYou skipped a step. The order is fixed: services → countries → providers. Never guess a country id; take it from the countries response.
400Please re-pick service, country and providerYour buy body is missing one of service, country, maxPrice, or maxPrice came through as 0. Send the pool's maxPrice exactly as returned (a decimal, not the ₦ price).
400That provider just sold out — please pick another oneStock moves constantly. Re-call /providers and pick a fresh pool. Nothing was charged.
400Insufficient balanceTop up your wallet. The ₦ amount charged is the pool's price field, not maxPrice.
400Provider did not return a numberUpstream hiccup. Nothing was charged — just retry, and if it repeats pick a different pool or country.
401UnauthorizedThe buy call needs a signed-in session token; the three browse calls do not.
502Any upstream error textThe upstream number provider is unreachable or rejected the request. Wait a few seconds and retry the same call — this is never caused by your request body.
Golden rule: price and stock are re-verified server-side at the moment of purchase, so a stale pool can only ever fail the buy — it can never overcharge you. Any failed buy leaves your balance untouched.

Boost API — social media growth (v1)

Resell followers, likes, views and subscribers from your own app. Same catalogue, same prices and the same upstream panel that powers the King Zee Social Hub Boost page. Every call uses your X-API-Key / X-API-Secret pair, and orders are charged to your King Zee Social Hub wallet in NGN.

There are no webhooks. The upstream panel does not send callbacks, so neither do we — poll GET /api/v1/boost/order/:id (it refreshes live from the provider on every call). Once every 2–5 minutes is plenty.
MethodEndpointBody / QueryReturns
GET /api/v1/boost/services platform, search (both optional) Catalogue: serviceId, name, platform, min, max, refill, pricePer1000Ngn
POST /api/v1/boost/quote { serviceId, quantity } Exact priceNgn — nothing is charged
POST /api/v1/boost/order { serviceId, link, quantity } orderId, status, priceNgn, new balanceNgn
GET /api/v1/boost/order/:orderId Live status: status, bucket, startCount, remains
GET /api/v1/boost/orders status=all|pending|delivered|failed, limit 1–200 Your boost order history, newest first
POST /api/v1/boost/order/:orderId/refill Requests a refill (completed orders on refill-enabled services only)
GET /api/v1/boost/balance { balanceNgn, currency }

Full flow with cURL — browse, price, order, then poll.

# 1. Find a service curl "$BASE/api/v1/boost/services?platform=Instagram&search=followers" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" # 2. Price 500 followers (nothing is charged) curl -X POST "$BASE/api/v1/boost/quote" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" \ -H "Content-Type: application/json" \ -d '{"serviceId":"1435","quantity":500}' # 3. Place the order (wallet is debited, auto-refunded if the provider rejects it) curl -X POST "$BASE/api/v1/boost/order" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" \ -H "Content-Type: application/json" \ -d '{"serviceId":"1435","link":"https://instagram.com/yourpage","quantity":500}' # 4. Poll until bucket != "pending" curl "$BASE/api/v1/boost/order/ORDER_ID_HERE" \ -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET"

Node.js — with the error handling you actually want in production.

const BASE = 'https://klslogs.com'; const HEADERS = { 'Content-Type': 'application/json', 'X-API-Key': process.env.KLS_API_KEY, 'X-API-Secret': process.env.KLS_API_SECRET, }; async function kls(path, options = {}) { const res = await fetch(BASE + path, { ...options, headers: HEADERS }); const text = await res.text(); let body; try { body = JSON.parse(text); } catch { throw new Error(`Non-JSON reply (HTTP ${res.status}): ${text.slice(0, 200)}`); } if (!res.ok || body.ok === false) { const err = new Error(body.error || `HTTP ${res.status}`); err.status = res.status; err.retryable = res.status === 502 || res.status === 503; throw err; } return body; } async function boost(link, quantity) { const { services } = await kls('/api/v1/boost/services?platform=Instagram&search=followers'); const service = services.find(s => quantity >= s.min && quantity <= s.max); if (!service) throw new Error('No service accepts that quantity'); const quote = await kls('/api/v1/boost/quote', { method: 'POST', body: JSON.stringify({ serviceId: service.serviceId, quantity }), }); const { balanceNgn } = await kls('/api/v1/boost/balance'); if (balanceNgn < quote.priceNgn) throw new Error('Top up your King Zee Social Hub wallet first'); const order = await kls('/api/v1/boost/order', { method: 'POST', body: JSON.stringify({ serviceId: service.serviceId, link, quantity }), }); for (;;) { // no webhooks upstream — poll await new Promise(r => setTimeout(r, 120000)); const { order: o } = await kls(`/api/v1/boost/order/${order.orderId}`); if (o.bucket !== 'pending') return o; } } boost('https://instagram.com/yourpage', 500) .then(o => console.log('Finished:', o.status)) .catch(e => console.error('Boost failed:', e.message, '| retryable:', !!e.retryable));

PHP — same flow with cURL and proper exceptions.

<?php function kls($path, $method = 'GET', $payload = null) { $ch = curl_init('https://klslogs.com' . $path); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_TIMEOUT => 40, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-API-Key: ' . getenv('KLS_API_KEY'), 'X-API-Secret: ' . getenv('KLS_API_SECRET'), ], ]); if ($payload !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); $raw = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); $cerr = curl_error($ch); curl_close($ch); if ($raw === false) throw new Exception("Network error: $cerr"); $data = json_decode($raw, true); if (json_last_error() !== JSON_ERROR_NONE) throw new Exception("Non-JSON reply (HTTP $status)"); if ($status >= 400 || (isset($data['ok']) && $data['ok'] === false)) throw new Exception(($data['error'] ?? "HTTP $status") . " [$status]"); return $data; } try { $quote = kls('/api/v1/boost/quote', 'POST', ['serviceId' => '1435', 'quantity' => 500]); echo "Price: NGN {$quote['priceNgn']}\n"; $order = kls('/api/v1/boost/order', 'POST', [ 'serviceId' => '1435', 'link' => 'https://instagram.com/yourpage', 'quantity' => 500, ]); echo "Order {$order['orderId']} placed\n"; $state = kls('/api/v1/boost/order/' . $order['orderId']); echo "Status: {$state['order']['status']}\n"; } catch (Exception $e) { echo 'Boost failed: ' . $e->getMessage() . "\n"; }

Boost errors and how to fix them

StatusMeaningFix
400quantity out of range / bad linkThe response names the field. Quantity must sit between the service's min and max; the link must be a full http(s):// URL.
401Missing or invalid key pairCheck both headers, or regenerate in Settings → API Access.
402Insufficient wallet balanceTop up, then retry. Never blind-retry this one.
404Unknown serviceId or orderRe-fetch /services — the panel drops services regularly.
502Provider rejected or unreachableNothing was charged — your wallet is refunded inside the same request. Retry after a minute.
503Boosting switched offAn admin disabled it, or the provider key is missing. Retry later.
Idempotency: POST /order is not idempotent. If a request times out on your side, call GET /api/v1/boost/orders?limit=5 to check whether it landed before sending it again.

Errors

StatusMeaningWhat to do
401Missing or invalid API key/secretDouble-check the X-API-Key/X-API-Secret headers are set and match exactly what's shown in Settings API Access. Regenerating your key there invalidates the old one immediately.
403Account restrictedYour account has been limited — contact support, this isn't something a retry fixes.
404Listing not found or no longer availableRe-fetch /listings or /numbers/options — the item may have sold out or been removed since you last checked.
400Insufficient balance, sold out, or invalid requestCheck the response body's error field for the specific reason — it's always a plain-English message, not just the code.
402Insufficient balance (numbers endpoints)Deposit funds before retrying — no partial/temporary state is created, so it's safe to just retry once the balance is topped up.
409No numbers currently available for that provider/countryThis is temporary stock, not a config issue — wait a few seconds and retry, or check /numbers/options again in case that provider/country is no longer listed at all.
Numbers specifically: your money is only ever taken if a real number was actually issued — a failed /buy-number call never touches your balance, so it's always safe to just retry. Once you do have an order, it auto-refunds on its own if no code arrives in time — you don't have to call /cancel-number unless you want your balance back sooner than that.
Back to Settings