Eviworx
Docs

API Keys API

API keys are role-based machine identities for external systems (server-to-server). An API key authenticates via the X-API-Key header and receives the permissions of its assigned role — it runs through the same RBAC matrix as a logged-in user (unified actor). Keys are managed under /api/api-keys; this is an admin-only function and only possible with a logged-in user.

🔑
Features
✓ Role-based permissions (roleId → role)
✓ SHA-256 hash (plaintext key shown only once)
✓ IP whitelist (IPv4/IPv6 + CIDR)
✓ Rate limit per minute
✓ Expiry date (expiresAt)
✓ Deactivate (reversible) and delete permanently
✓ Usage statistics (lastUsedAt)
✓ Audit logging (SECURITY domain)

Authentication & Permissions

There are two separate layers: MANAGING keys (/api/api-keys) and USING a key against the normal API routes.

Action Permission
All management routes (read/create/update/delete/activate)settings.manageRoles
Use a key (against API routes)permissions of the assigned role

User context required (no API key): All /api/api-keys routes require a logged-in user AND settings.manageRoles. An X-API-Key is rejected here with 403 — so an API key cannot manage itself or other keys.

Unified actor: On use, the permissions of the key's role apply, checked exactly as for signed-in users. If the key has no active role assigned, every request is rejected with 403 API_KEY_NO_ROLE. Details: Permissions & RBAC.

Endpoints Overview

All routes: settings.manageRoles + logged-in user.

Method Endpoint Description
GET/api/api-keysList all keys (without plaintext key, newest first)
POST/api/api-keysCreate key (201; plaintext key visible ONLY here)
PUT/api/api-keys/:idUpdate key
DELETE/api/api-keys/:idPermanently delete key
POST/api/api-keys/:id/deactivateDeactivate key (isActive=false, reversible)
POST/api/api-keys/:id/reactivateReactivate key

Deactivate via POST /:id/deactivate; alternatively isActive can be set via PUT /:id.

Fields

Field Type Description
nameString (1–100)Display name, unique (duplicate → 409)
descriptionString? (≤500)Optional description
roleIdString?Assigned role — determines the key's permissions. If the role is deleted, the field is set to null.
allowedIPsString[]IP whitelist (single IPv4/IPv6 or CIDR, e.g. 10.0.0.0/24). Empty = usable from anywhere.
rateLimitInt? (1–10000)Max requests per minute. null = unlimited.
expiresAtDateTime? (ISO 8601)Expiry date. Expired keys are rejected with 403 on use.
isActiveBooleanActive status. Always true on create; changeable only via update / (de)activate.
keyStringResponse only. Stored as a SHA-256 hash; the plaintext (prefix apk_) is returned exclusively on creation.
keyPreviewStringFirst 12 chars for display (e.g. apk_Ab12Cd34…)
roleNameString?Response only: display name of the role (resolved from roleId)
lastUsedAtDateTime?Response only: last usage timestamp (updated on every request)

Create Key

POST /api/api-keys
{
  "name": "SAP Integration",
  "description": "API key for SAP ticket sync",
  "roleId": "clx-integration-role",
  "rateLimit": 1000,
  "allowedIPs": ["192.168.1.100", "10.0.0.0/24"],
  "expiresAt": "2027-12-31T23:59:59Z"
}

Response (201 Created)

{
  "success": true,
  "message": "API key created successfully. Save this key - it will not be shown again!",
  "apiKey": {
    "id": "clx...",
    "name": "SAP Integration",
    "key": "apk_8sJ2...full-plaintext-key-only-shown-once...",
    "description": "API key for SAP ticket sync",
    "isActive": true,
    "rateLimit": 1000,
    "createdAt": "2026-06-18T10:00:00Z",
    "expiresAt": "2027-12-31T23:59:59Z",
    "roleId": "clx-integration-role",
    "roleName": "Integration",
    "allowedIPs": ["192.168.1.100", "10.0.0.0/24"]
  }
}
IMPORTANT: The full plaintext key (key) is returned ONLY ONCE on creation. After that all endpoints only return keyPreview (first 12 chars). Store the key securely right away!

Using a Key

The key is sent in the X-API-Key header (not as a Bearer token):

curl https://your-instance.com/api/tickets \
  -H "X-API-Key: apk_8sJ2...your-key..."

Runtime checks (in this order)

Check On failure
X-API-Key header present401 API_KEY_REQUIRED
Key exists (SHA-256 lookup)401 INVALID_API_KEY
isActive403 API_KEY_DISABLED
Not expired (expiresAt)403 API_KEY_EXPIRED
Client IP in allowedIPs (if set)403 IP_NOT_ALLOWED
Rate limit not exceeded (if set)429 RATE_LIMIT_EXCEEDED (+ Retry-After)

The rate limit counts in a 60-second window. If the counter store (Redis) is unreachable, key requests are rejected with 503 SERVICE_UNAVAILABLE (+ Retry-After) so that the limit is never silently lifted. The IP check understands CIDR ranges and normalizes IPv4-mapped IPv6 (::ffff:…).

Error Codes

HTTP Error Code Description
400Validation error (e.g. invalid IP/CIDR, invalid date format, rateLimit outside 1–10000)
403FORBIDDENMissing settings.manageRoles or no user context (X-API-Key)
404API_KEY_NOT_FOUNDKey does not exist
409API_KEY_NAME_EXISTSA key with this name already exists

The 401/403/429/503 codes in the "Runtime checks" table apply to USING a key; the codes above apply to MANAGING keys.

Security & Best Practices

  • Use only for server-to-server integrations, never in the browser/frontend.
  • Choose the role by least privilege — the key gets exactly its permissions.
  • Set an IP whitelist and expiry date; configure a rate limit against abuse.
  • Rotate keys (deactivate old, create new) and store them securely (secret store).
  • All key actions (create/update/delete/(de)activate) are recorded in the audit log (SECURITY domain).
Permissions & RBAC →
Unified actor, role matrix, caching
Authentication →
User auth, MFA, SSO, sessions
Users, Roles & Groups →
Roles assignable to a key