Entwicklerdokumentation

Die Kalkhan API ermöglicht es Ihnen, Lizenzprüfung, Aktivierung und Händler-Integration direkt aus Ihren eigenen Systemen heraus abzuwickeln. Dieses Dokument beschreibt den Aufbau von Anfragen und Antworten, das Authentifizierungsverfahren und die Fehlercodes der Endpunkte. Überblick Die Kalkhan API ist eine ressourcenorientierte REST-Schnittstelle. Alle Anfrage- und Antwortkörper werden im Format JSON mit der Zeichenkodierung UTF-8 übertragen. Verbindungen müssen mit TLS 1.2 oder höher verschlüsselt sein; unverschlüsselte Anfragen (HTTP) werden abgelehnt. Base URLhttps://api.kalkhan.com.tr/v1 ProtokollHTTPS / TLS 1.2+ (verpflichtend) DatenformatJSON · Content-Type: application/json; charset=utf-8 ZeichenkodierungUTF-8 DatumsformatISO 8601 (UTC), z. B. 2027-07-23T00:00:00Z Ratenbegrenzung120 Anfragen pro Minute (je Schlüssel) Alle Endpunktadressen werden an die Base URL angehängt. Die vollständige Adresse des Endpunkts zur Lizenzprüfung lautet beispielsweise https://api.kalkhan.com.tr/v1/licenses/verify. Einrichtung & Einstieg Wenn Sie die Integration von Grund auf beginnen, führen Sie die folgenden Schritte der Reihe nach aus. Der gesamte Vorgang dauert im Schnitt 15 Minuten und erfordert keinerlei Kalkhan Software auf Ihrem Server – eine Umgebung, die HTTPS-Anfragen senden kann, genügt. Voraussetzungen Ein freigegebenes Kalkhan Händlerkonto (Antrag über das Kontaktformular) Eine Serverumgebung mit Unterstützung für TLS 1.2 oder höher (PHP 7.4+, Node.js 16+, .NET 6+, Python 3.8+ usw.) Eine Möglichkeit, den API-Schlüssel serverseitig abzulegen (Umgebungsvariablen empfohlen) Schritt für Schritt Melden Sie sich im Händlerportal an. Sobald Ihr Konto von der Administration freigegeben wurde, erhalten Sie Zugang zum Portal. Erzeugen Sie einen API-Schlüssel. Legen Sie im Portal unter “API-Schlüssel” zunächst einen Testschlüssel mit dem Präfix klk_test_ an. Definieren Sie die Umgebungsvariablen. Tragen Sie Schlüssel und Base URL in die Konfiguration Ihrer Anwendung ein (Beispiel unten). Senden Sie die erste Anfrage. Rufen Sie den Health-Endpunkt auf, um die Verbindung zu prüfen. Hinterlegen Sie Ihre Webhook-Adresse. Tragen Sie im Portal Ihre HTTPS-Webhook-Adresse ein, um Lizenzereignisse in Echtzeit zu empfangen. Gehen Sie live. Nach abgeschlossenen Tests wechseln Sie auf einen klk_live_-Schlüssel; im Code ändert sich nur der Schlüssel selbst. 1) Umgebungskonfiguration # .env KALKHAN_API_URL=https://api.kalkhan.com.tr/v1 KALKHAN_API_KEY=klk_test_xxxxxxxxxxxxxxxx KALKHAN_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx 2) Verbindungstest curl -s https://api.kalkhan.com.tr/v1/ping \ -H "Authorization: Bearer $KALKHAN_API_KEY" # Erfolgreiche Antwort { "ok": true, "env": "test", "dealer": "BYI-1001" } Tipp: In der Testumgebung erzeugte Lizenzen fließen nicht in die Abrechnung ein und lassen sich jederzeit löschen. Testen Sie vor dem Live-Betrieb die vollständigen Abläufe zum Erstellen, Prüfen und Stornieren von Lizenzen mit dem Testschlüssel. Authentifizierung API-Anfragen werden über das Bearer-Schema mit Ihrem API-Schlüssel autorisiert. Der Schlüssel muss bei jeder Anfrage im Header Authorization mitgesendet werden. Authorization: Bearer klk_live_xxx Content-Type: application/json; charset=utf-8 Accept: application/json Ihren API-Schlüssel erzeugen und widerrufen Sie im Bereich “API-Schlüssel” Ihres Händlerportals. Für die Testumgebung gelten Schlüssel mit dem Präfix klk_test_, für die Produktivumgebung klk_live_. Sicherheitshinweis: Der API-Schlüssel ist ein geheimes Zugangsmerkmal und gehört ausschließlich auf den Server. Betten Sie ihn nicht in Browser-Code, mobile App-Pakete oder öffentliche Code-Repositories ein. Bei Verdacht auf Kompromittierung widerrufen Sie ihn sofort im Portal und erzeugen einen neuen. Lizenzprüfung Dient dazu, Gültigkeit, Produkt und Restlaufzeit eines Lizenzschlüssels abzufragen. Lizenzschlüssel haben das Format KLKN-XXXX-XXXX-XXXX-XXXX. MethodeEndpunktBerechtigung POST/licenses/verifyBearer API-Schlüssel Anfrage 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" } Antwort (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" } FeldTypBeschreibung statusstringactive, expired, suspended oder cancelled productstringAnzeigename des Produkts, zu dem die Lizenz gehört editionstringhome, business oder enterprise seatsintegerGesamtzahl der von der Lizenz abgedeckten Geräte expiresAtstringAblaufdatum im ISO-8601-Format (UTC) Für einen ungültigen oder im System nicht vorhandenen Schlüssel wird 404 not_found zurückgegeben, für einen formal fehlerhaften Schlüssel 400 invalid_request. Lizenz erstellen (Händler) Dient autorisierten Händlern dazu, im Namen von Endkunden neue Lizenzen zu erzeugen. Dieser Endpunkt kann ausschließlich mit API-Schlüsseln aufgerufen werden, die über eine Händlerberechtigung verfügen. MethodeEndpunktBerechtigung POST/licensesHändler-API-Schlüssel Anfrage 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" } } Antwort (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" } Bei Geschäftskunden (wenn edition den Wert business oder enterprise hat) ist die Übermittlung von customer.taxId (Steuernummer), customer.taxOffice (Finanzamt) und customer.address für die Rechnungsstellung verpflichtend. Fehlen diese Felder, wird die Anfrage mit 400 invalid_request abgelehnt. Bei Privatlizenzen (home) sind die Steuerfelder optional. Innerhalb kurzer Zeit wiederholte Anfragen für denselben Kunden und dasselbe Produkt werden mit 409 duplicate beantwortet; um doppelte Lizenzen zu vermeiden, empfehlen wir, Ihrer Anfrage den Header Idempotency-Key hinzuzufügen. Händler-API Für die Abfrage des eigenen Lizenzbestands und der Verkaufsübersicht stehen Händlern zwei Endpunkte zur Verfügung. MethodeEndpunktBeschreibung GET/dealer/licensesSeitenweise Liste der Lizenzen des Händlers GET/dealer/statsÜbersicht zu Verkaufszahlen, Umsatz und anstehenden Verlängerungen Parameter für die Seitennavigation ParameterStandardBeschreibung page1Nummer der angezeigten Seite (beginnt bei 1) limit25Datensätze pro Seite (höchstens 100) status—Optionaler Filter: active, expired, cancelled Anfrage und Antwort 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 } } Der Endpunkt GET /dealer/stats liefert eine Periodenübersicht: Gesamtzahl aktiver Lizenzen, monatliche Verkaufszahlen, Gesamtumsatz sowie die Anzahl der Lizenzen, die in den nächsten 30 Tagen ablaufen. Webhooks Mit Webhooks übermitteln Sie Änderungen im Lebenszyklus einer Lizenz in Echtzeit an Ihre Systeme. Die Zieladresse legen Sie im Händlerportal fest; Kalkhan sendet an diese Adresse eine POST-Anfrage mit JSON-Körper. EreignisWann wird es ausgelöst? license.createdWenn eine neue Lizenz erstellt wird license.expiredWenn die Laufzeit der Lizenz endet license.cancelledWenn eine Lizenz storniert oder eine Rückerstattung verarbeitet wird Beispiel für einen Ereigniskörper 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" } } Signaturprüfung Jede Webhook-Anfrage wird mit dem Header X-Kalkhan-Signature signiert. Die Signatur ist der Hash aus Zeitstempel und rohem Anfragekörper, berechnet mit HMAC-SHA256 und Ihrem geheimen Webhook-Schlüssel. Prüfen Sie die Signatur unbedingt, bevor Sie die Anfrage verarbeiten, und weisen Sie Zeitstempel zurück, die älter als 5 Minuten sind. // Node.js — Signaturprüfung const crypto = require('crypto'); function dogrula(rawBody, header, secret) { const parts = Object.fromEntries( header.split(',').map(p => p.split('=')) ); const beklenen = crypto .createHmac('sha256', secret) .update(parts.t + '.' + rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(beklenen), Buffer.from(parts.v1) ); } Antwortet Ihr Server nicht mit 2xx, wird das Ereignis in wachsenden Abständen (1 Min., 5 Min., 30 Min., 2 Std., 12 Std.) bis zu fünfmal erneut zugestellt. Gehen Sie davon aus, dass dasselbe Ereignis mehrfach eintreffen kann, und prüfen Sie anhand des Feldes id auf Wiederholungen. Fehlercodes Fehler werden mit den üblichen HTTP-Statuscodes zurückgegeben und enthalten im Körper einen maschinenlesbaren code sowie eine erläuternde message. HTTPCodeBeschreibung 400invalid_requestParameter fehlt oder hat ein falsches Format 401unauthorizedAPI-Schlüssel fehlt, ist ungültig oder wurde widerrufen 403forbiddenDer Schlüssel hat keine Berechtigung für diesen Endpunkt 404not_foundAngeforderte Lizenz oder Ressource nicht gefunden 409duplicateDatensatz existiert bereits; doppelte Anfrage blockiert 429rate_limitedRatenbegrenzung überschritten; warten Sie den Header Retry-After ab 500server_errorUnerwarteter Fehler auf Serverseite Beispiel einer Fehlerantwort HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 { "error": { "code": "invalid_request", "message": "Das Feld customer.taxId ist für Geschäftslizenzen verpflichtend.", "field": "customer.taxId", "requestId": "req_01J9X2K7QF" } } Wenn Sie eine Supportanfrage stellen, beschleunigt die Angabe der requestId aus der Antwort die Bearbeitung erheblich. SDK & Beispiele Offizielle SDKs befinden sich in Vorbereitung. Bis dahin rufen Sie die API direkt über HTTP auf. Nachfolgend finden Sie die Lizenzprüfung als cURL- und JavaScript-Beispiel. 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; // serverseitig aufbewahren async function lisansDogrula(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 } } lisansDogrula('KLKN-4F2A-9C71-B3D8-A15E', 'WIN-8f2c41ab9d') .then(lisans => console.log(lisans.status, lisans.expiresAt)) .catch(err => console.error('Prüfung fehlgeschlagen:', err.message)); Diese Beispiele sind ausschließlich für den serverseitigen Einsatz gedacht. Betten Sie den API-Schlüssel nicht in Code ein, der im Browser ausgeführt wird; leiten Sie Prüfanfragen aus Ihren Client-Anwendungen über Ihr eigenes Backend. Geschlossene Beta Die API befindet sich derzeit in einer geschlossenen Beta; den Zugang beantragen Sie unter bilgi@kalkhan.com.tr. Während der Beta sind rückwärtsinkompatible Änderungen an den Endpunkten möglich.