API reference

Every endpoint CloudLoader Platform exposes. CloudLoader calls these automatically — this is for anyone building something beyond it: a custom launcher, a status page, a website integration.

Authentication — four different credentials

Each one grants different access. Using the wrong one for a job either fails outright or (worse) over-shares.

api_key (pk_...) — public. Safe to embed in distributed code. Identifies a product, nothing more.
secret_key (sk_...) — private. Never leaves your dashboard. Only needed for /api/license/check.
server_token (srv_...) — a customer's own credential, from their portal. Identifies their server, not a product.
X-Signature header — HMAC-SHA256 of the raw request body using a product's Tebex webhook secret. Only relevant for the Tebex webhook endpoint.
POST /api/server/config server_token

The one call CloudLoader makes at startup. Given just a server token, returns every attached product ready to use — no manual per-product setup. Revoked or suspended licenses are silently excluded, so a customer server never has to handle that itself.

Rate limit: 30/min

Request
{
  "server_token": "srv_..."
}
Response
{
  "server_name": "My Main Server",
  "products": [
    {
      "product_id": "PRD-123456",
      "product_name": "Dispatch System",
      "api_key": "pk_...",
      "license_key": "XXXX-XXXX-XXXX-XXXX",
      "api_base": "https://this-or-a-custom-domain.com",
      "channel": "stable"
    }
  ]
}
GET /api/ping none

Unauthenticated health check. Used to verify a custom domain is actually reaching this platform before it goes live for anyone.

Rate limit: unlimited

Response
{ "ok": true, "platform": "CloudLoader Platform" }
POST /api/license/activate/<product_id> api_key (public)

Validates a license using only the public api_key — this is what a distributed script should call, since the secret_key never has to leave your dashboard. Also accepts an optional channel ("stable" or "beta").

Rate limit: 120/min

Request
{
  "api_key": "pk_...",
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "server_id": "optional, e.g. sv_hostname"
}
Response (200) / invalid (401, 403, or 404)
{ "valid": true, "product": { "name": "...", "version": "..." } }
{ "valid": false, "message": "License is revoked." }
POST /api/license/check/<product_id> api_key + secret_key

The elevated version of license activation — requires the private secret_key too. Meant for your own server-side integrations (a website checking a customer's status), never for anything distributed to customers.

Rate limit: 120/min

Request
{
  "api_key": "pk_...",
  "secret_key": "sk_...",
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "server_id": "optional"
}
Response
{
  "valid": true,
  "product": { "name": "...", "version": "..." },
  "license": { "status": "active", "expires_at": null }
}
POST /api/update/check/<product_id> api_key (public)

Compares a version string you send against the product's current published version.

Rate limit: 60/min

Request
{ "api_key": "pk_...", "current_version": "1.0.0" }
Response
{ "latest_version": "1.2.0", "update_available": true }
POST /api/module/list/<product_id> api_key + valid license

Lists modules available to a specific license. Pass channel: "beta" to also receive beta overrides — you still get every stable module too; beta never means fewer modules, just newer ones where a developer has published an override.

Rate limit: 60/min

Request
{
  "api_key": "pk_...",
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "channel": "stable"
}
Response
{
  "modules": [
    { "name": "menu", "display_name": "Test Menu", "side": "server", "version": "1.0.0", "channel": "stable" }
  ]
}
POST /api/module/download/<product_id>/<module_name> api_key + valid license

Returns the actual Lua source for one module. This is what makes code "delivered from the platform" — it never has to exist as a file on the customer's disk.

Rate limit: 60/min

Request
{
  "api_key": "pk_...",
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "channel": "stable"
}
Response
{
  "name": "menu",
  "side": "server",
  "version": "1.0.0",
  "channel": "stable",
  "code": "RegisterCommand(...)"
}
POST /api/config/load/<product_id> api_key + valid license

Returns whatever JSON object a developer has published as that product's remote config — values they can change live without republishing any code. {} if nothing is set.

Rate limit: 60/min

Request
{ "api_key": "pk_...", "license_key": "XXXX-XXXX-XXXX-XXXX" }
Response
{ "config": { "maxCalls": 10, "cooldownSeconds": 30 } }
POST /api/tebex/webhook/<product_id> X-Signature (HMAC-SHA256)

Where Tebex purchase events land. The signature is HMAC-SHA256 of the raw request body using the product's webhook secret (from the product's Tebex settings page) — this is what you paste into Tebex's own webhook configuration, not something you call directly.

Rate limit: 60/min

Request body
{
  "email": "customer@example.com",
  "package_id": "optional - filtered against integration setting",
  "quantity": 1
}
Response
{ "status": "ok", "license_keys": ["XXXX-XXXX-XXXX-XXXX"] }

Every endpoint above rejects invalid credentials with a real error status (401/403/404), never a silent 200 with empty data — safe to treat any non-200 response as "this call failed" without inspecting the body first.