Skip to main content

Authentication

The LeonAI API supports two authentication methods:

  • API keys (X-API-Key: <key>) — for scripts and server-to-server integrations.
  • JWT bearer tokens (Authorization: Bearer <token>) — for the dashboard and account-management endpoints.

Most developer endpoints accept either method. Account endpoints (auth, users, billing, teams, and API-key management) require a JWT, and POST /api/v1/track/conversions requires an API key with the analytics:write scope.

API keys​

API keys are the recommended way to call the API programmatically. Send the key in the X-API-Key header:

curl https://api.short.leonai.io/api/v1/links \
-H "X-API-Key: lk_live_your_key_here"

Keys are prefixed (lk_live_... / lk_test_...), stored only as a hash, and shown in full exactly once — at creation time.

Scopes​

Each key carries one or more scopes. An endpoint's required scope is noted in its description; a 403 is returned if the key lacks it.

ScopeGrants
links:readList, read, and export links
links:writeCreate, update, delete, and bulk-import links
analytics:readRead link/account analytics, real-time stats, and conversion reports
analytics:writeRecord conversions (POST /api/v1/track/conversions)
domains:readList and read custom domains
domains:writeCreate, verify, and delete custom domains
webhooks:readList and read webhook endpoints and delivery logs
webhooks:writeCreate, update, and delete webhook endpoints

Grant the narrowest set of scopes a key needs. A key used only to create links needs just links:write (and links:read if it also reads them back).

Creating a key​

  1. Open the LeonAI dashboard.
  2. Go to Settings → API Keys.
  3. Click Create API key, name it, and select its scopes.
  4. Copy the key immediately — it is shown only once. Store it in a secret manager or environment variable, never in source control.

Programmatically, keys are created with a JWT via POST /api/v1/api-keys (an API key can never mint, re-scope, or revoke API keys — that always requires a JWT):

curl -X POST https://api.short.leonai.io/api/v1/api-keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "CI deploy key",
"scopes": ["links:read", "links:write"],
"environment": "live"
}'

The response includes the raw key once:

{
"success": true,
"data": {
"id": "key_...",
"name": "CI deploy key",
"key": "lk_live_...",
"prefix": "lk_live",
"scopes": ["links:read", "links:write"],
"createdAt": "2026-07-10T12:00:00.000Z"
},
"message": "API key created successfully. Save it now - you won't be able to see it again!"
}

JWT bearer tokens​

JWTs are issued by POST /api/v1/auth/signup and POST /api/v1/auth/login and refreshed via POST /api/v1/auth/refresh. Send the access token as a bearer token:

curl https://api.short.leonai.io/api/v1/auth/me \
-H "Authorization: Bearer <access_token>"

Use JWTs for account operations (managing API keys, billing, teams, 2FA, GDPR data export/deletion). For integrations and automation, prefer API keys.

Token flow​

A successful login returns an access token and a refresh token:

{
"success": true,
"data": {
"user": { "id": "…", "email": "you@example.com", "tier": "pro", "emailVerified": true },
"tokens": { "accessToken": "…", "refreshToken": "…", "expiresIn": 604800 }
}
}
  • Access token lifetime defaults to 7 days (expiresIn is seconds).
  • Refresh token lifetime defaults to 30 days. Exchange it at POST /api/v1/auth/refresh for a fresh pair (the old refresh token is rotated out).
  • POST /api/v1/auth/logout revokes the current session; POST /api/v1/auth/logout-all revokes every session.

Two-factor challenge​

If the account has 2FA enabled, login returns no tokens — instead it returns { requiresTwoFactor: true, pendingToken }. Complete the login by posting the pendingToken plus a TOTP code (or recovery code) to POST /api/v1/auth/2fa/verify, which then returns the normal token pair.

Conversion tracking is API-key only

POST /api/v1/track/conversions does not accept a JWT — it requires an API key with the analytics:write scope (and the Business+ conversionTracking feature). See the Analytics guide.

Rate limiting​

All /api/v1/* endpoints are rate limited per subscription tier. Every response includes these headers:

HeaderMeaning
X-RateLimit-LimitRequests allowed in the current window
X-RateLimit-RemainingRequests remaining in the window
X-RateLimit-ResetWhen the window resets

When you exceed the limit, the API responds with 429 Too Many Requests and a Retry-After header (in seconds). The planned TypeScript SDK (not published yet) will surface these as a rateLimit object on every response and retry idempotent requests automatically, honoring Retry-After.

const page = await leonai.links.list();
page.rateLimit; // { limit, remaining, reset } | undefined
leonai.rateLimit; // most recent rate-limit state seen by this client

See the tier table for per-tier request quotas.