API Documentation

With the LisansX REST API you can pull the product list and stock levels into your own site, place orders and receive delivery codes instantly. Authentication, endpoints and PHP, Node.js and Python examples are below.

API keys are issued to resellers only. Anyone can read the documentation; sending requests requires an active reseller package. Your key is created when your reseller application is approved.

Authentication

Every request is signed with three headers. Because the signature covers the timestamp, HTTP method, path and raw body together, a request cannot be altered in transit or replayed.

HeaderValue
X-Api-KeyYour API key
X-TimestampUnix seconds — must be within ±300 s of the server time
X-SignatureHex signature generated with the formula below
signingKey = sha256_hex(api_secret)
signature  = hmac_sha256_hex(signingKey, timestamp + "\n" + METHOD + "\n" + path + "\n" + rawBody)
  • path: the path plus the query string, if any (/api/v1/products?limit=50). Query parameters are part of the signature too — sign exactly the URL you request.
  • rawBody: the exact JSON you send; an empty string for GET requests.
  • Do not re-serialise the body after signing it — even the slightest difference breaks the signature.

Endpoints

MethodPathDescription
GET /api/v1/products All products on sale, at your reseller prices
GET /api/v1/products/{id} Single product details and stock status
POST /api/v1/order Create an order — returns the delivery codes on success
GET /api/v1/order/{order_no} Order status and delivered codes
GET /api/v1/balance Your current balance

The per-minute request limit is set per reseller account. When exceeded, 429 rate_limited is returned. All error responses use the format {"success": false, "error": "...", "message": "..."}.

Integration Examples

Ready to copy and paste

<?php
final class LisansXClient
{
    public function __construct(
        private string $baseUrl,
        private string $apiKey,
        private string $apiSecret
    ) { $this->baseUrl = rtrim($baseUrl, '/'); }

    public function request(string $method, string $path, ?array $body = null): array
    {
        $method  = strtoupper($method);
        $bodyRaw = $body !== null ? json_encode($body, JSON_UNESCAPED_UNICODE) : '';
        $ts      = (string)time();

        // İmzalama anahtarı = ham secret'ın SHA-256 hex karşılığı
        $signingKey = hash('sha256', $this->apiSecret);
        $signature  = hash_hmac('sha256', $ts . "\n" . $method . "\n" . $path . "\n" . $bodyRaw, $signingKey);

        $ch = curl_init($this->baseUrl . $path);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST  => $method,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTPHEADER     => [
                'X-Api-Key: '   . $this->apiKey,
                'X-Timestamp: ' . $ts,
                'X-Signature: ' . $signature,
                'Content-Type: application/json',
            ],
        ]);
        if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyRaw);

        $raw = curl_exec($ch);
        curl_close($ch);
        return json_decode((string)$raw, true) ?: ['success' => false, 'error' => 'invalid_response'];
    }
}

// --- Kullanım ---
$api = new LisansXClient('https://lisansx.net', 'YOUR_API_KEY', getenv('LISANSX_SECRET'));

$products = $api->request('GET', '/api/v1/products');
$order    = $api->request('POST', '/api/v1/order', ['product_id' => 1, 'qty' => 1]);

if (!empty($order['success'])) {
    foreach ($order['data']['codes'] as $code) {
        echo "Teslim edilen kod: $code\n";
    }
} else {
    error_log('LisansX hatasi: ' . ($order['message'] ?? 'bilinmiyor'));
}

Common Errors

401 invalid_signature
You may have skipped deriving the signing key as sha256(secret).
401 invalid_timestamp
Your server clock is out of sync. Synchronise it with NTP.
403 ip_not_allowed
An IP restriction is set and your request comes from an IP that is not on the list.
409 replayed_request
The same signed POST request arrived a second time (replay protection). Sign every request with a fresh timestamp; if you place two orders for the same product within the same second, add a unique "nonce" field to the body (e.g. your own order number).
429 rate_limited
You exceeded the per-minute limit; spread your requests out over time.
409 out_of_stock
The product is out of stock or not available in the requested quantity (the available field gives the remaining quantity). No order is created and no balance is charged. Check stock with GET /api/v1/products/{id} before taking payment from your own customer; the stock.changed webhook notifies you instantly when a product sells out or comes back.
409 price_changed
If you sent the optional "max_unit_price" with the order and the current unit price exceeds it, no order is created; unit_price gives the current price.
402 delivery_failed
The order was created but the product could not be delivered (e.g. it sold out at the source at the last moment). The amount is refunded to your balance automatically.
Message on WhatsApp Message on Telegram