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
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
{
"data": {
"product": "pro",
"active": true,
"status": "ACTIVE",
"expiresAt": "2027-01-14T09:30:00.000Z"
},
"requestId": "req_2Fd8nQe5Ry6t"
}{
"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.