Developer Documentation

The Kalkhan API lets you run license verification, activation and dealer integration from your own systems. This document describes the request/response structure of each endpoint, the authentication method and the error codes. Overview The Kalkhan API is a resource-oriented REST interface. All request and response bodies are transferred as JSON with UTF-8 character encoding. Connections must be encrypted with TLS 1.2 or above; unencrypted (HTTP) requests are rejected. Base URLhttps://api.kalkhan.com.tr/v1 ProtocolHTTPS / TLS 1.2+ (required) Data formatJSON · Content-Type: application/json; charset=utf-8 Character encodingUTF-8 Date formatISO 8601 (UTC), e.g. 2027-07-23T00:00:00Z Rate limit120 requests per minute (per key) Every endpoint path is appended to the base URL. The full address of the license verification endpoint, for example, is https://api.kalkhan.com.tr/v1/licenses/verify. Setup & Getting Started If you are starting the integration from scratch, follow the steps below in order. The whole process takes around 15 minutes and requires no Kalkhan software on your server — an environment that can send HTTPS requests is all you need. Prerequisites An approved Kalkhan dealer account (apply through the contact form) A server environment supporting TLS 1.2 or above (PHP 7.4+, Node.js 16+, .NET 6+, Python 3.8+ and similar) A configuration method that keeps the API key on the server side (environment variables recommended) Step-by-step setup Sign in to your dealer panel. Panel access opens once your account has passed administrator approval. Generate an API key. In the panel’s “API Keys” section, start by creating a test key prefixed with klk_test_. Define your environment variables. Add the key and the base URL to your application configuration (example below). Send your first request. Call the health endpoint to confirm the connection. Register your webhook address. Define your HTTPS webhook address in the panel to receive license events in real time. Go live. Once testing is complete, switch to the klk_live_ key; nothing in your code changes but the key itself. 1) Environment configuration # .env KALKHAN_API_URL=https://api.kalkhan.com.tr/v1 KALKHAN_API_KEY=klk_test_xxxxxxxxxxxxxxxx KALKHAN_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx 2) Connection test curl -s https://api.kalkhan.com.tr/v1/ping \ -H "Authorization: Bearer $KALKHAN_API_KEY" # Successful response { "ok": true, "env": "test", "dealer": "BYI-1001" } Tip: Licenses created in the test environment are never billed and can be deleted at any time. Before taking the integration live, run through the full license creation, verification and cancellation flows with your test key. Authentication API requests are authorized with the Bearer scheme using your API key. The key must be sent in the Authorization header of every request. Authorization: Bearer klk_live_xxx Content-Type: application/json; charset=utf-8 Accept: application/json You can create and revoke API keys in the “API Keys” section of your dealer panel. Keys prefixed with klk_test_ are used for the test environment, and klk_live_ for production. Security note: the API key is a secret credential — keep it on the server side only. Never embed it in a browser, a mobile app bundle or a public code repository. If you suspect a key has leaked, revoke it in the panel immediately and generate a new one. License Verification Used to query the validity, product and remaining term of a license key. License keys follow the KLKN-XXXX-XXXX-XXXX-XXXX format. MethodEndpointAuthorization POST/licenses/verifyBearer API key Request POST /v1/licenses/verify HTTP/1.1 Host: api.kalkhan.com.tr Authorization: Bearer klk_live_xxx Content-Type: application/json; charset=utf-8 { "key": "KLKN-4F2A-9C71-B3D8-A15E", "deviceId": "WIN-8f2c41ab9d", "productId": "kalkhan-av-windows" } Response (200 OK) { "key": "KLKN-4F2A-9C71-B3D8-A15E", "status": "active", "product": "Kalkhan Anti-Virüs (Windows)", "edition": "business", "seats": 25, "seatsUsed": 11, "expiresAt": "2027-03-14T23:59:59Z" } FieldTypeDescription statusstringactive, expired, suspended or cancelled productstringDisplay name of the product the license belongs to editionstringhome, business or enterprise seatsintegerTotal number of devices covered by the license expiresAtstringExpiry date in ISO 8601 format (UTC) An unknown key returns 404 not_found, and a malformed key returns 400 invalid_request. License Creation (Dealer) Used by authorized dealers to issue a new license on behalf of an end customer. This endpoint can only be called with API keys that carry dealer permissions. MethodEndpointAuthorization POST/licensesDealer API key Request POST /v1/licenses HTTP/1.1 Host: api.kalkhan.com.tr Authorization: Bearer klk_live_xxx Content-Type: application/json; charset=utf-8 { "productId": "kalkhan-av-windows", "edition": "business", "seats": 25, "customer": { "name": "Örnek Bilişim A.Ş.", "email": "muhasebe@ornekbilisim.com.tr", "taxId": "1234567890", "taxOffice": "Ümraniye", "address": "Mithatpaşa Cd. No:116, Ümraniye/İstanbul" } } Response (201 Created) { "key": "KLKN-7B10-CE45-2F93-D8A6", "status": "active", "product": "Kalkhan Anti-Virüs (Windows)", "edition": "business", "seats": 25, "amount": 34750.00, "currency": "TRY", "expiresAt": "2027-07-23T23:59:59Z" } For corporate sales (when edition is business or enterprise), the fields customer.taxId (tax identification number), customer.taxOffice (tax office) and customer.address are mandatory so that an invoice can be issued. Requests missing these fields are rejected with 400 invalid_request. For individual (home) licenses the tax fields are optional. Repeated requests for the same customer and product within a short window are answered with 409 duplicate; adding an Idempotency-Key header is recommended to prevent duplicate licenses. Dealer API Two endpoints let dealers query their own license portfolio and sales summary. MethodEndpointDescription GET/dealer/licensesPaginated list of the dealer’s licenses GET/dealer/statsSales count, revenue and upcoming renewal summary Pagination parameters ParameterDefaultDescription page1Page number to display (starts at 1) limit25Records per page (100 at most) status—Optional filter: active, expired, cancelled Request and response GET /v1/dealer/licenses?page=2&limit=25&status=active HTTP/1.1 Host: api.kalkhan.com.tr Authorization: Bearer klk_live_xxx { "data": [ { "key": "KLKN-4F2A-9C71-B3D8-A15E", "status": "active", "product": "Kalkhan Anti-Virüs (Windows)", "edition": "business", "seats": 25, "customer": "Örnek Bilişim A.Ş.", "expiresAt": "2027-03-14T23:59:59Z" } ], "pagination": { "page": 2, "limit": 25, "total": 143, "totalPages": 6 } } The GET /dealer/stats endpoint returns a periodic summary: total active licenses, monthly sales count, total revenue and the number of licenses expiring in the next 30 days. Webhooks Use webhooks to push license lifecycle changes to your systems in real time. You define the target address in the dealer panel, and Kalkhan sends a JSON body to that address with a POST request. EventWhen is it triggered? license.createdWhen a new license is created license.expiredWhen a license reaches the end of its term license.cancelledWhen a license is cancelled or a refund is processed Example event body POST /webhooks/kalkhan HTTP/1.1 X-Kalkhan-Signature: t=1784937600,v1=9f8c1d2b7e4a63f05c8b1a9d4e7f2c30b6a5d8e1f4c7b0a3d6e9f2c5b8a1d4e7 Content-Type: application/json; charset=utf-8 { "id": "evt_01J9X2K7QF", "event": "license.created", "createdAt": "2026-07-23T09:41:02Z", "data": { "key": "KLKN-7B10-CE45-2F93-D8A6", "product": "Kalkhan Anti-Virüs (Windows)", "edition": "business", "seats": 25, "expiresAt": "2027-07-23T23:59:59Z" } } Signature verification Every webhook request is signed with the X-Kalkhan-Signature header. The signature is an HMAC-SHA256 digest of the timestamp and the raw request body, computed with your webhook secret. Always verify the signature before processing a request, and reject timestamps older than 5 minutes. // Node.js — signature verification const crypto = require('crypto'); function verify(rawBody, header, secret) { const parts = Object.fromEntries( header.split(',').map(p => p.split('=')) ); const expected = crypto .createHmac('sha256', secret) .update(parts.t + '.' + rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(parts.v1) ); } If your server does not return a 2xx response, the event is retried up to 5 times at increasing intervals (1 min, 5 min, 30 min, 2 h, 12 h). Assume the same event may arrive more than once and de-duplicate on the id field. Error Codes Errors are returned with standard HTTP status codes and carry a machine-readable code together with a descriptive message in the body. HTTPCodeDescription 400invalid_requestA missing or malformed parameter was sent 401unauthorizedAPI key missing, invalid or revoked 403forbiddenThe key is not authorized for this endpoint 404not_foundThe requested license or resource was not found 409duplicateThe record already exists; the duplicate request was blocked 429rate_limitedRate limit exceeded; wait for the Retry-After header 500server_errorAn unexpected error occurred on the server side Example error response HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 { "error": { "code": "invalid_request", "message": "The customer.taxId field is required for corporate licenses.", "field": "customer.taxId", "requestId": "req_01J9X2K7QF" } } Quoting the requestId from the response when you open a support ticket helps us investigate quickly. SDK & Examples Official SDKs are in preparation. In the meantime you can call the API directly over HTTP. Below are the cURL and JavaScript equivalents of a license verification request. cURL curl -X POST https://api.kalkhan.com.tr/v1/licenses/verify \ -H "Authorization: Bearer klk_live_xxx" \ -H "Content-Type: application/json; charset=utf-8" \ -d '{ "key": "KLKN-4F2A-9C71-B3D8-A15E", "deviceId": "WIN-8f2c41ab9d", "productId": "kalkhan-av-windows" }' JavaScript (fetch) const API_KEY = process.env.KALKHAN_API_KEY; // keep this on the server side async function verifyLicense(key, deviceId) { const res = await fetch( 'https://api.kalkhan.com.tr/v1/licenses/verify', { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify({ key, deviceId, productId: 'kalkhan-av-windows' }) } ); if (!res.ok) { const { error } = await res.json(); throw new Error(`${error.code}: ${error.message}`); } return res.json(); // { status, product, edition, seats, expiresAt } } verifyLicense('KLKN-4F2A-9C71-B3D8-A15E', 'WIN-8f2c41ab9d') .then(license => console.log(license.status, license.expiresAt)) .catch(err => console.error('Verification failed:', err.message)); These examples are for server-side use only. Do not place the API key in code that runs in a browser; route verification requests from your client applications through your own backend service. Closed beta The API is currently in closed beta; request access at bilgi@kalkhan.com.tr. Backwards-incompatible endpoint changes may occur while the beta is running.