Knox Wizard Partner API

Version 1

The Partner API lets approved resellers and distributors sell Knox Wizard licenses automatically from their own website, shop or bot: create a customer account, then activate or renew its license. Every activation is paid from your prepaid credit balance.

1 credit = 1 USD. Accounts and credit top-ups are issued by Knox Wizard support. No website? Use the Partner Portal to do the same things in your browser with the same credits.

Authentication

Base URL:

https://api.knoxwizard.com/partner/v1

Send your API key on every request as a bearer token (or an X-API-Key header):

Authorization: Bearer kw_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
Keep your key secret. Call the API only from your server (PHP, Node, Python…), never from browser JavaScript or an app you distribute: anyone with the key can spend your credits. If it leaks, ask support for a new key; the old one stops working instantly. We can also lock your key to your server's IP addresses.

Rate limit: 120 requests per minute per key. Requests and responses are JSON.

Plans & prices

PlanDurationResellerDistributor
3m3 months$20$15
6m6 months$25$20
12m12 months$30$25

Your account type decides your price. GET /plans always returns your current prices. Activating on an account that is still active adds the time on top of the remaining time.

Recommended flow

  1. Your customer pays you.
  2. New customer: POST /accounts with their email and plan. The account is created and licensed in one step.
    Existing customer (renewal): POST /licenses/activate with their email and plan.
  3. Always send your order number as reference. If a request times out, retry with the same reference; you are never charged twice.
  4. Give the customer their login (email + password) and the download link knoxwizard.com. Sign-in codes are emailed, so the email must be real. Customers can change their password with "Forgot password" in the app.

Creating an account without a plan is free: it is created expired (no access) and can be activated later.

Balance

GET/partner/v1/me
{ "ok": true, "partner": { "id": "…", "type": "reseller", "name": "Acme GSM", "email": "[email protected]", "company": "" },
  "balance": 270, "currency": "USD" }

Plans

GET/partner/v1/plans
{ "ok": true, "type": "reseller", "currency": "USD", "balance": 270,
  "plans": [ { "plan": "3m", "label": "3 Months", "months": 3, "cost": 20 },
             { "plan": "6m", "label": "6 Months", "months": 6, "cost": 25 },
             { "plan": "12m", "label": "12 Months", "months": 12, "cost": 30 } ] }

Create an account

POST/partner/v1/accounts
FieldRequiredDescription
emailyesCustomer's real email (login + sign-in codes).
passwordnoMin 6 characters. If omitted, a password is generated and returned once as password.
planno3m, 6m or 12m: create and license (charged). Omit for a free expired account.
referencerecommendedYour order ID (1–64 chars: letters, digits, . _ : -).
POST /partner/v1/accounts
{ "email": "[email protected]", "plan": "3m", "reference": "ORD-10045" }

201 Created
{ "ok": true,
  "account": { "email": "[email protected]", "status": "active", "expiry": "2026-12-27",
               "days_left": 92, "licensed": true, "devices_used_30d": 0 },
  "password": "k7QmZ2xR9p",
  "charge": { "plan": "3m", "cost": 20, "reference": "ORD-10045", "transaction_id": "…", "created_at": 1790500000 },
  "balance": 250 }

409 account_exists means the email is already registered. Activate it instead. With 402 insufficient_credits nothing is created.

Activate / renew a license

POST/partner/v1/licenses/activate

Works on any Knox Wizard customer account (renewals of accounts created elsewhere too).

POST /partner/v1/licenses/activate
{ "email": "[email protected]", "plan": "12m", "reference": "ORD-10046" }

200 OK
{ "ok": true,
  "account": { "email": "[email protected]", "status": "active", "expiry": "2027-12-27", "days_left": 457, "licensed": true, … },
  "charge": { "plan": "12m", "cost": 30, "reference": "ORD-10046", … },
  "balance": 220 }

Look up an account

GET/partner/v1/[email protected]

Only accounts you created or licensed are visible; others return 404.

Transaction history

GET/partner/v1/transactions?limit=50&offset=0

Your credit ledger, newest first. type: topup, deduct, charge, refund; amount is signed.

Idempotency

A reference is charged at most once. Sending it again, even at the same moment, returns the original result with "idempotent_replay": true and no new charge.

Errors

Errors return "ok": false, a machine-readable code and a readable error. A failed request is never charged.

HTTPcodeMeaning
400invalid_planUnknown plan code.
400invalid_email / invalid_passwordBad email, or password shorter than 6.
400invalid_reference / invalid_bodyBad reference, or body is not a JSON object.
401invalid_api_keyMissing, wrong or revoked key.
402insufficient_creditsTop up. Response includes balance and cost.
403partner_disabled / ip_not_allowedAccess suspended, or IP not in your allowlist.
403account_disabledThe customer account is blocked by support.
404account_not_foundNo such account (or not visible to you).
409account_existsEmail already registered. Activate it instead.
429rate_limitedSlow down.
500server_errorTemporary; retry with the same reference.

Examples

cURL

curl -X POST https://api.knoxwizard.com/partner/v1/accounts \
  -H "Authorization: Bearer $KW_API_KEY" -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","plan":"3m","reference":"ORD-10045"}'

PHP

<?php
function kw_api(string $method, string $path, ?array $body = null): array {
    $ch = curl_init('https://api.knoxwizard.com/partner/v1' . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . getenv('KW_API_KEY'), 'Content-Type: application/json'],
        CURLOPT_POSTFIELDS     => $body ? json_encode($body) : null,
    ]);
    $res = json_decode(curl_exec($ch), true) ?: ['ok' => false, 'error' => curl_error($ch)];
    curl_close($ch);
    return $res;
}

$order = ['email' => $email, 'plan' => '3m', 'reference' => 'ORD-' . $orderId];
$res = kw_api('POST', '/accounts', $order);
if (!$res['ok'] && ($res['code'] ?? '') === 'account_exists') {
    $res = kw_api('POST', '/licenses/activate', $order);   // renewal
}

Node.js

const kw = (method, path, body) => fetch(`https://api.knoxwizard.com/partner/v1${path}`, {
  method, headers: { Authorization: `Bearer ${process.env.KW_API_KEY}`, "Content-Type": "application/json" },
  body: body ? JSON.stringify(body) : undefined
}).then(r => r.json());

let r = await kw("POST", "/accounts", { email, plan: "12m", reference: `ORD-${orderId}` });
if (!r.ok && r.code === "account_exists") r = await kw("POST", "/licenses/activate", { email, plan: "12m", reference: `ORD-${orderId}` });

Python

import os, requests
def kw(method, path, body=None):
    return requests.request(method, f"https://api.knoxwizard.com/partner/v1{path}",
        headers={"Authorization": f"Bearer {os.environ['KW_API_KEY']}"}, json=body, timeout=30).json()

print(kw("GET", "/me")["balance"])

Questions? Contact Knox Wizard support. © Knox Wizard