Skip to content

Developers

Small to integrate. Predictable to run.

Native SDKs where you need them, a plain HTTPS + JSON API everywhere else, and conventions that stay out of your way.

SDKs

TypeScript, Python and C++.

Each SDK pins your app's Ed25519 public key, verifies every response, and raises errors that carry the API's stable error code.

TypeScript
npm i @aroli/sdk
Python
pip install aroli
C++
#include <aroli/aroli.hpp> - libcurl + libsodium
Read the SDK guide →
main.tsnpm i @aroli/sdk
import { Aroli, AroliError } from "@aroli/sdk";

const aroli = new Aroli({
  appId: "app_8f2k1x9q",            // public - safe to ship
  publicKey: "<your app's Ed25519 key>", // pinned: responses are verified
});

try {
  const session = await aroli.login({ username, password, hwid: machineId() });
  await session.redeem(licenseKey);           // binds the key to this user + device
  if (!(await session.hasEntitlement("pro"))) showUpgrade();
  session.startHeartbeat();                   // keeps the session alive
} catch (err) {
  if (err instanceof AroliError && err.code === "device_mismatch") {
    showError("This account is linked to another device.");
  }
}

API principles

Conventions you can rely on.

The same rules apply to every endpoint, so once you've integrated one you know how the rest behave.

  • Versioned under /api/v1

    Every endpoint lives under a version prefix. Breaking changes are reserved for a new version; additive changes (new fields, new endpoints) can appear within v1, so ignore fields you don't know.

  • Two APIs, two trust levels

    The client API is called from your shipped software with only the public app ID. The management API is called from your servers with a secret key. They never share credentials.

  • Request IDs on everything

    Every response - success or error - includes a requestId in the body and an X-Request-Id header. Quote it when you contact support and we can find the exact call.

  • Idempotency keys

    Send an Idempotency-Key header with management POST, PATCH and DELETE requests. A retry with the same key and body returns the original response instead of acting twice.

  • Predictable rate limits

    Limits are applied per application and IP on the client API and per key on the management API. Responses include X-RateLimit-Limit and X-RateLimit-Remaining; a 429 includes Retry-After.

  • Signed client responses

    Client API responses carry X-Aroli-Signature, X-Aroli-Timestamp and X-Aroli-Key-Id. Verify the Ed25519 signature over `${timestamp}.${nonce}.${body}` with your pinned key.

Response format

One envelope for success, one for errors.

Successful responses wrap the payload in data. Errors return a machine-readable code, a human-readable message safe to show to users, and the request ID.

  • invalid_credentials
  • device_mismatch
  • device_limit_reached
  • license_invalid
  • license_already_redeemed
  • activation_limit_reached
  • session_expired
  • entitlement_missing
  • rate_limited
All error codes →
200 OK · GET /api/v1/client/entitlements/pro
{
  "data": {
    "product": "pro",
    "active": true,
    "status": "ACTIVE",
    "expiresAt": "2027-01-14T09:30:00.000Z"
  },
  "requestId": "req_2Fd8nQe5Ry6t"
}
409 Conflict · POST /api/v1/client/licenses/redeem
{
  "error": {
    "code": "license_already_redeemed",
    "message": "That license key has already been used."
  },
  "requestId": "req_9Pq1sXk7Vb3c"
}

Build your first integration today.

Create an application, connect an SDK and issue your first license key. The free plan has everything you need to build and test your integration.