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.
| Header | Value |
|---|---|
X-Api-Key | Your API key |
X-Timestamp | Unix seconds — must be within ±300 s of the server time |
X-Signature | Hex 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
| Method | Path | Description |
|---|---|---|
| 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
availablefield gives the remaining quantity). No order is created and no balance is charged. Check stock withGET /api/v1/products/{id}before taking payment from your own customer; thestock.changedwebhook 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_pricegives 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.