Developer API Documentation

Integrate licensing, hardware device binding, and subscription validation into Flutter, Windows, macOS, Linux, and web applications.

Base API Endpoint: https://keyauth.workss.in/api/v1

LicenseEngine provides a self-hosted licensing architecture comparable to modern software authorization platforms. All requests and responses communicate strictly via standard JSON over HTTPS.

Authentication Flow

Authentication follows a two-stage session handshake:

  1. Initialization (Handshake): The client calls POST /api/v1/init with its public app_id and client version. The server verifies app status, maintenance mode, and minimum semantic version, then issues a temporary high-entropy session_token.
  2. Authentication: The client presents the session_token alongside the user's license key and machine hwid to POST /api/v1/license. The server validates expiration, subscription, blacklists, binds machine HWID atomically, and elevates the session to authenticated.
  3. Heartbeat & Verification: While running, applications periodically ping POST /api/v1/heartbeat to confirm the session, license, and bans remain valid.

Client-Secret Security Model

Core Security Principle

Desktop and mobile client software (Flutter, C#, C++, Python binaries) can be decompiled and reverse engineered. Never embed server-side administrative credentials or master database secrets inside compiled client software!

Client apps only ever embed their public app_id. Session tokens are generated cryptographically using high-entropy random bytes, stored server-side as SHA-256 hashes, and slid automatically upon authenticated activity.

POST /api/v1/init
Initialize Application Session

Establishes a temporary API session token and verifies client version compatibility.

Request Body Parameters
ParameterTypeRequiredDescription
app_idstringYesPublic Application ID (e.g. app_xxxxxxxx).
versionstringNoSemantic version of the client software (e.g. 1.0.0).
Example Request (cURL)
curl -X POST "https://keyauth.workss.in/api/v1/init" \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "YOUR_APP_PUBLIC_ID",
    "version": "1.0.0"
  }'
Success Response (200 OK)
{
  "success": true,
  "message": "Application initialized successfully.",
  "data": {
    "session_token": "7a3f892b1049281c7e90...",
    "expires_in": 900,
    "application": {
      "name": "My App",
      "version": "1.0.0",
      "maintenance": false
    }
  }
}
POST /api/v1/license
Authenticate License Key

Validates license key status, calculates first activation expiry, and binds machine HWID.

Request Body Parameters
ParameterTypeRequiredDescription
session_tokenstringYesToken obtained from /init.
licensestringYesUser license key string.
hwidstringYesMachine hardware fingerprint.
device_namestringNoDevice / computer hostname.
platformstringNoOperating system (e.g. Windows, Android).
Success Response (200 OK)
{
  "success": true,
  "message": "Authentication successful.",
  "data": {
    "expires_at": "2027-10-05T18:30:00Z",
    "is_lifetime": false,
    "subscriptions": [
      {
        "name": "Premium Tier",
        "slug": "premium",
        "level": 2
      }
    ],
    "device_limit": 1,
    "registered_devices": 1
  }
}
POST /api/v1/heartbeat
Lightweight Session Heartbeat

Keep-alive ping to ensure authenticated sessions, licenses, and bans remain valid.

curl -X POST "https://keyauth.workss.in/api/v1/heartbeat" \
  -H "Content-Type: application/json" \
  -d '{
    "session_token": "YOUR_SESSION_TOKEN"
  }'

Error Codes Reference

Error CodeHTTP StatusDescription
INVALID_REQUEST422Form validation failure or missing required fields.
INVALID_APP404Public Application ID does not exist.
APP_DISABLED403Application has been paused or disabled by administrator.
APP_MAINTENANCE403Application is in maintenance mode.
VERSION_OUTDATED426Client software version is below minimum supported version.
INVALID_SESSION401Session token does not exist or has expired.
SESSION_EXPIRED401Session timed out due to inactivity.
INVALID_LICENSE404License key does not exist.
LICENSE_EXPIRED403License validity duration has lapsed.
LICENSE_DISABLED403License has been temporarily disabled.
LICENSE_BANNED403License was banned by admin.
HWID_MISMATCH403Hardware device limit reached for this license.
HWID_BANNED403Specific machine HWID is blacklisted.
IP_BANNED403Client IP address is blacklisted.
INVALID_CREDENTIALS401Username or password incorrect.
USER_BANNED403User account is banned.
RATE_LIMITED429Too many requests sent within rate limit window.

Flutter / Dart Client SDK

Complete production-ready client class using the standard Dart http package.

import 'dart:convert';
import 'package:http/http.dart' as http;

class LicenseAuthClient {
  final String baseUrl;
  final String appId;
  String? sessionToken;

  LicenseAuthClient({required this.baseUrl, required this.appId});

  /// Initialize application session
  Future<Map<String, dynamic>> init({String version = '1.0.0'}) async {
    final response = await http.post(
      Uri.parse('$baseUrl/api/v1/init'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'app_id': appId, 'version': version}),
    );

    final data = jsonDecode(response.body);
    if (data['success'] == true) {
      sessionToken = data['data']['session_token'];
    }
    return data;
  }

  /// Authenticate license key with machine HWID
  Future<Map<String, dynamic>> authenticateLicense({
    required String license,
    required String hwid,
    String? deviceName,
    String? platform,
  }) async {
    if (sessionToken == null) {
      throw Exception('Session not initialized. Call init() first.');
    }

    final response = await http.post(
      Uri.parse('$baseUrl/api/v1/license'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'session_token': sessionToken,
        'license': license,
        'hwid': hwid,
        'device_name': deviceName,
        'platform': platform,
      }),
    );

    return jsonDecode(response.body);
  }

  /// Lightweight heartbeat verification
  Future<bool> heartbeat({String? hwid}) async {
    if (sessionToken == null) return false;
    try {
      final res = await http.post(
        Uri.parse('$baseUrl/api/v1/heartbeat'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({'session_token': sessionToken, 'hwid': hwid}),
      );
      final json = jsonDecode(res.body);
      return json['success'] == true;
    } catch (_) {
      return false;
    }
  }

  /// Terminate session on app close
  Future<void> logout() async {
    if (sessionToken == null) return;
    await http.post(
      Uri.parse('$baseUrl/api/v1/logout'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'session_token': sessionToken}),
    );
    sessionToken = null;
  }
}

// ==========================================
// Usage Example in Flutter:
// ==========================================
void main() async {
  final auth = LicenseAuthClient(
    baseUrl: 'https://keyauth.workss.in',
    appId: 'YOUR_APP_ID',
  );

  // 1. Initialize
  final initRes = await auth.init(version: '1.0.0');
  if (initRes['success'] != true) {
    print('Init failed: ${initRes['error']['message']}');
    return;
  }

  // 2. Authenticate
  final authRes = await auth.authenticateLicense(
    license: 'VB-XXXX-XXXX-XXXX',
    hwid: 'DEVICE-UNIQUE-ID',
    deviceName: 'MyPhone',
    platform: 'Android',
  );

  if (authRes['success'] == true) {
    print('Access granted! Expires: ${authRes['data']['expires_at']}');
  } else {
    print('Denied: ${authRes['error']['message']}');
  }
}

Python Client SDK

Reusable class using Python requests with automatic session persistence.

import requests
import platform

class LicenseAuth:
    def __init__(self, base_url: str, app_id: str):
        self.base_url = base_url.rstrip('/')
        self.app_id = app_id
        self.session_token = None

    def init(self, version: str = "1.0.0") -> dict:
        url = f"{self.base_url}/api/v1/init"
        res = requests.post(url, json={"app_id": self.app_id, "version": version}, timeout=10)
        data = res.json()
        if data.get("success"):
            self.session_token = data["data"]["session_token"]
        return data

    def authenticate_license(self, license_key: str, hwid: str, device_name: str = None) -> dict:
        if not self.session_token:
            raise RuntimeError("Must call init() before authenticating.")
        url = f"{self.base_url}/api/v1/license"
        payload = {
            "session_token": self.session_token,
            "license": license_key,
            "hwid": hwid,
            "device_name": device_name or platform.node(),
            "platform": platform.system()
        }
        res = requests.post(url, json=payload, timeout=10)
        return res.json()

    def heartbeat(self) -> bool:
        if not self.session_token:
            return False
        url = f"{self.base_url}/api/v1/heartbeat"
        res = requests.post(url, json={"session_token": self.session_token}, timeout=5)
        return res.json().get("success", False)

# Example Usage:
if __name__ == "__main__":
    auth = LicenseAuth("https://keyauth.workss.in", "YOUR_APP_ID")
    auth.init("1.0.0")
    result = auth.authenticate_license("VB-XXXX-XXXX-XXXX", "MY-HWID-STRING")
    if result.get("success"):
        print("Success! Expiry:", result["data"]["expires_at"])
    else:
        print("Error:", result["error"]["message"])

C# (.NET) Client SDK

Native asynchronous integration with HttpClient and System.Text.Json.

using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class LicenseAuthClient
{
    private readonly HttpClient _http = new HttpClient();
    private readonly string _baseUrl;
    private readonly string _appId;
    public string SessionToken { get; private set; }

    public LicenseAuthClient(string baseUrl, string appId)
    {
        _baseUrl = baseUrl.TrimEnd('/');
        _appId = appId;
    }

    public async Task<JsonDocument> InitAsync(string version = "1.0.0")
    {
        var payload = JsonSerializer.Serialize(new { app_id = _appId, version });
        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await _http.PostAsync($"{_baseUrl}/api/v1/init", content);
        var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

        if (json.RootElement.GetProperty("success").GetBoolean())
        {
            SessionToken = json.RootElement.GetProperty("data").GetProperty("session_token").GetString();
        }
        return json;
    }

    public async Task<JsonDocument> AuthenticateLicenseAsync(string license, string hwid)
    {
        var payload = JsonSerializer.Serialize(new {
            session_token = SessionToken,
            license = license,
            hwid = hwid,
            device_name = Environment.MachineName,
            platform = "Windows"
        });
        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await _http.PostAsync($"{_baseUrl}/api/v1/license", content);
        return JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    }
}

C++ Client (libcurl)

Standard C++ implementation using libcurl for high-performance Windows / Linux binaries.

#include <iostream>
#include <string>
#include <curl/curl.h>

static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

std::string SendPost(const std::string& url, const std::string& jsonPayload) {
    CURL* curl = curl_easy_init();
    std::string response;
    if (curl) {
        struct curl_slist* headers = NULL;
        headers = curl_slist_append(headers, "Content-Type: application/json");

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonPayload.c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);

        curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        curl_slist_free_all(headers);
    }
    return response;
}