King Store

Developers

King Store Reseller API โ€” keys, webhooks, and documentation.

API Status
Checking...

API Keys

Loading your API keys...

Webhook Configuration

Receive order/bulk-order status change events at this URL. Deliveries are signed with HMAC-SHA256 in the X-KingStore-Signature header โ€” verify it using your webhook secret.

Recent API Orders

Loading...

Recent API Requests

Loading...

API Documentation

1. Generate an API Key

Click Generate New Key in the API Keys section above. The full secret key is shown exactly once, immediately after generation โ€” copy it and store it somewhere safe (a password manager or secrets store) right away, because King Store never stores the raw key and cannot show it to you again. If you lose it, revoke it and generate a new one. You can have up to 5 active keys at a time.

2. Authentication

Send your key as a bearer token on every request:

Authorization: Bearer ks_live_YOUR_API_KEY

A missing, malformed, revoked, or disabled key always returns the same generic 401 โ€” King Store never reveals which part of the check failed.

3. API Base URL

{{BASE_URL}}

Every endpoint below is relative to this base URL.

4. Balance โ€” GET /v1/balance

Your wallet balance. API purchases are debited from this same wallet.

{{BASE_URL}}/v1/balance

Request:

curl -H "Authorization: Bearer ks_live_YOUR_API_KEY" \
  {{BASE_URL}}/v1/balance

Response:

{
  "status": true,
  "data": { "balance": 128.50, "currency": "GHS" }
}

5. Packages โ€” GET /v1/packages

Every currently available data package and its live price. Always resolve package_id from this endpoint before a purchase โ€” a stale or hardcoded ID can go unavailable at any time.

{{BASE_URL}}/v1/packages

Request:

curl -H "Authorization: Bearer ks_live_YOUR_API_KEY" \
  {{BASE_URL}}/v1/packages

Response:

{
  "status": true,
  "data": [
    {
      "id": "b2e1...package-uuid",
      "network": "MTN",
      "name": "MTN 1GB",
      "size_gb": 1,
      "validity": "No Expiry",
      "price": 4.30
    }
  ]
}

6. Purchase โ€” POST /v1/purchase

Buys one data package for one recipient, paid from your wallet. client_reference is required and must be unique per API key โ€” retrying the same reference returns the original order (already_processed: true) instead of purchasing again, so it's safe to retry on a timeout.

{{BASE_URL}}/v1/purchase

Request:

curl -X POST -H "Authorization: Bearer ks_live_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "package_id": "b2e1...package-uuid",
    "recipient": "0241234567",
    "client_reference": "MYORDER123"
  }' \
  {{BASE_URL}}/v1/purchase

Response:

{
  "status": true,
  "already_processed": false,
  "data": {
    "order_reference": "KS-7F3A9C2E1B",
    "client_reference": "MYORDER123",
    "network": "MTN",
    "recipient": "0241234567",
    "amount": 4.30,
    "status": "paid"
  }
}

7. Order Status โ€” GET /v1/orders/{reference}

Look up one order (single purchase) by its order_reference. Only returns orders belonging to your own account.

{{BASE_URL}}/v1/orders/KS-7F3A9C2E1B

Request:

curl -H "Authorization: Bearer ks_live_YOUR_API_KEY" \
  {{BASE_URL}}/v1/orders/KS-7F3A9C2E1B

Response:

{
  "status": true,
  "data": {
    "order_reference": "KS-7F3A9C2E1B",
    "client_reference": "MYORDER123",
    "network": "MTN",
    "package": "1GB",
    "recipient": "0241234567",
    "amount": 4.30,
    "status": "delivered",
    "payment_status": "paid",
    "created_at": "2026-08-01T10:00:00.000Z",
    "updated_at": "2026-08-01T10:02:30.000Z"
  }
}

Bulk Purchase โ€” POST /v1/bulk-purchase

Same package for up to 150 unique recipients in one paid batch. recipients accepts an array of numbers or a single comma/newline-separated string; duplicates are removed automatically. client_reference is required and unique per API key, same retry-safe behavior as /v1/purchase.

{{BASE_URL}}/v1/bulk-purchase

Request:

curl -X POST -H "Authorization: Bearer ks_live_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "package_id": "b2e1...package-uuid",
    "recipients": ["0241234567", "0551234567"],
    "client_reference": "BULK-CLIENT-001"
  }' \
  {{BASE_URL}}/v1/bulk-purchase

Response:

{
  "status": true,
  "already_processed": false,
  "data": {
    "bulk_reference": "KS-BULK-08E9DC34",
    "client_reference": "BULK-CLIENT-001",
    "network": "MTN",
    "recipient_count": 2,
    "total": 8.60,
    "status": "paid"
  }
}

Bulk Order Status โ€” GET /v1/bulk-orders/{reference}

{{BASE_URL}}/v1/bulk-orders/KS-BULK-08E9DC34

Response:

{
  "status": true,
  "data": {
    "bulk_reference": "KS-BULK-08E9DC34",
    "client_reference": "BULK-CLIENT-001",
    "network": "MTN",
    "package": "1GB",
    "recipient_count": 2,
    "delivered_count": 1,
    "processing_count": 1,
    "failed_count": 0,
    "total": 8.60,
    "status": "processing",
    "created_at": "2026-08-01T10:00:00.000Z",
    "updated_at": "2026-08-01T10:02:30.000Z",
    "orders": [
      { "order_reference": "KS-A1B2C3D4E5", "recipient": "0241234567", "status": "delivered" },
      { "order_reference": "KS-F6G7H8I9J0", "recipient": "0551234567", "status": "processing" }
    ]
  }
}

There is also a lightweight GET /v1/ping that just confirms your key works: {{BASE_URL}}/v1/ping โ†’ {"status":true,"message":"King Store API is online"}.

Error Responses

Every error response has the shape { "status": false, "error": "..." }, sometimes with a machine-readable code and extra fields. HTTP status codes actually used:

401 Unauthorized  โ€” missing, malformed, revoked, or disabled API key
                    {"status":false,"error":"Invalid or missing API key."}

400 Bad Request   โ€” missing/invalid field, e.g.
                    {"status":false,"error":"package_id is required."}

                    or too many recipients on a bulk purchase:
                    {"status":false,"error":"You can purchase for a maximum of 150 numbers at a time.",
                     "code":"too_many_recipients","valid_count":151,"max":150}

                    or invalid recipient numbers on a bulk purchase:
                    {"status":false,"error":"Some recipient numbers are not valid Ghana numbers.",
                     "code":"invalid_recipients","invalid":["12345"],"valid_count":2,"duplicate_count":0}

402 Payment Required โ€” insufficient wallet balance:
                    {"status":false,"error":"Insufficient wallet balance.","code":"insufficient_balance",
                     "available_balance":5.00,"order_amount":13.10}

404 Not Found     โ€” {"status":false,"error":"Order not found."} / "Bulk order not found."

409 Conflict      โ€” a purchase with this client_reference is still being processed
                    (rare โ€” only when two requests race at the exact same instant;
                    a normal retry instead returns the original order with
                    "already_processed": true and HTTP 200)
                    {"status":false,"error":"This purchase is already being processed."}

429 Too Many Requests โ€” {"status":false,"error":"Too many requests. Please slow down."}

500 Internal Error โ€” {"status":false,"error":"We couldn't complete this purchase right now. Please try again."}

Webhook Setup & Signature Verification

Set your webhook URL (must be https://) in the Webhook Configuration section above. Saving it generates a fresh signing secret, shown once โ€” save it. King Store then POSTs a JSON event to your URL whenever one of your orders or bulk orders changes state. Delivery is always asynchronous: it never happens inline with a purchase request, and a slow or broken endpoint never blocks or delays anything.

Event types actually sent: order.processing, order.delivered, order.failed, bulk_order.processing, bulk_order.partially_completed, bulk_order.completed, bulk_order.failed.

Every delivery includes these headers:

Content-Type: application/json
X-KingStore-Event: order.delivered
X-KingStore-Signature: 5f9c1f...  (hex HMAC-SHA256 of the raw request body, using your webhook secret)

Example order-event body:

{
  "event_id": "6f0b1a2c-...",
  "event_type": "order.delivered",
  "timestamp": "2026-08-01T10:02:30.000Z",
  "order_reference": "KS-7F3A9C2E1B",
  "bulk_reference": null,
  "client_reference": "MYORDER123",
  "status": "delivered"
}

Example bulk-order-event body:

{
  "event_id": "9a3d5e7f-...",
  "event_type": "bulk_order.completed",
  "timestamp": "2026-08-01T10:05:00.000Z",
  "order_reference": null,
  "bulk_reference": "KS-BULK-08E9DC34",
  "total": 8.60,
  "delivered": 2,
  "processing": 0,
  "failed": 0
}

Verify the signature (Node.js example) โ€” recompute the HMAC over the exact raw request body you received and compare it to the X-KingStore-Signature header using a constant-time comparison:

const crypto = require("crypto");

function isValidSignature(rawBody, signatureHeader, webhookSecret) {
  const expected = crypto
    .createHmac("sha256", webhookSecret)
    .update(rawBody, "utf8")
    .digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(signatureHeader, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// Express example:
app.post("/webhooks/kingstore", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.header("X-KingStore-Signature");
  if (!isValidSignature(req.body, signature, process.env.KINGSTORE_WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }
  const event = JSON.parse(req.body);
  // event_id is stable across retries โ€” dedupe on it if you've seen it before.
  res.status(200).send("ok");
});

Rate Limits

Each API key is limited to 60 requests per 60 seconds. There is also a separate 60-requests-per-60-seconds limit per source IP address, checked before your key is even looked up. Exceeding either returns:

HTTP 429 Too Many Requests
{"status":false,"error":"Too many requests. Please slow down."}

Back off and retry after a short delay โ€” the limit is a rolling window, not a hard daily cap.

King Store
Dashboard Buy Data Bulk Purchase Airtime (Soon) Orders Bulk Orders Transactions Wallet Track Order Developers Support Settings Logout