Authentication
Create and manage API keys for the Kolbo Developer API.
All API requests require an API key passed via the X-API-Key header.
API Key Format
Keys follow the format kolbo_live_<60 hex characters> — the literal prefix kolbo_live_ plus 30 random bytes rendered as hex.
The kolbo_live_ prefix is mandatory. Any key that does not start with it is rejected as Invalid API key format before any lookup happens.
Creating a Key
Via Dashboard (Recommended)
Go to Developer Console and click Create Key.
Via API
The key-management endpoints under /api/api-keys sit behind the same authentication layer as the rest of the API, so either credential works: a JWT from your browser session, or an existing X-API-Key that carries write permission. The examples below use the JWT form because that is what the Developer Console does.
An API key with write permission can mint, reveal and revoke further API keys on the same account. Treat a write key as equivalent to full account access and scope your integrations accordingly.
curl -X POST https://api.kolbo.ai/api/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "My Integration", "permissions": ["read", "write"], "expiresInDays": 365}'Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Label for the key. Must be a non-empty string; whitespace is trimmed. An empty or non-string value returns 400. |
permissions | string[] | No | Any subset of read | write. Defaults to ["read", "write"]. Any other value returns 400 — admin keys cannot be self-created. |
expiresInDays | number | No | Defaults to 365. Parsed with parseInt, then clamped to 1–730. Out-of-range values are clamped rather than rejected (1000 → 730, -5 → 1); 0 and unparseable values fall back to 365. |
Returns 201 on success:
{
"status": true,
"data": {
"id": "key_id",
"keyPrefix": "kolbo_live_a1b2c3d4e...",
"name": "My Integration",
"permissions": ["read", "write"],
"createdAt": "2026-03-05T10:00:00Z",
"expiresAt": "2027-03-05T10:00:00Z"
},
"fullKey": "kolbo_live_abc123def456...",
"message": "API key created. You can view the full key again any time from this page."
}The full key is not one-time. It is stored encrypted alongside the validation hash, so you can retrieve it again with the reveal endpoint below or from the Developer Console.
Reveal a Key Again
curl https://api.kolbo.ai/api/api-keys/KEY_ID/reveal \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Returns { "status": true, "fullKey": "kolbo_live_..." }. Ownership is enforced in the lookup, so a key belonging to someone else is indistinguishable from one that does not exist (404).
Keys minted before the encrypted-copy feature existed cannot be revealed. They return 400 with This key was created before full-reveal was supported. Create a new key to view it in full. — the only fix is to create a replacement key.
keyPrefix (returned by the create, list and details endpoints) is the first 20 characters of the key followed by a literal .... It is a display label, not a usable credential.
Using the Key
Include it in every request via the X-API-Key header:
curl https://api.kolbo.ai/api/v1/models \
-H "X-API-Key: YOUR_API_KEY"JavaScript (fetch):
async function main() {
const response = await fetch("https://api.kolbo.ai/api/v1/models", {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
const data = await response.json();
console.log(data);
}
main();Python (requests):
import requests
response = requests.get(
"https://api.kolbo.ai/api/v1/models",
headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())Optional: Tagging a Session
Every request may additionally carry X-Kolbo-Caller-Session-Id, a stable identifier you choose for one run of your integration. Credit deductions made while it is present are tagged with it, so you can later ask what a whole run cost — see Credits & Billing.
| Header | Type | Required | Description |
|---|---|---|---|
X-Kolbo-Caller-Session-Id | string | No | 1–128 characters, matching [A-Za-z0-9._:-]+ only. A UUID is the expected shape. Anything longer, empty, or containing a character outside that set is silently discarded — the request still succeeds, it is just not tagged. |
curl https://api.kolbo.ai/api/v1/models \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Kolbo-Caller-Session-Id: run-2026-07-27-a"Managing Keys
List Keys
curl https://api.kolbo.ai/api/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Returns { "status": true, "data": [ ... ] }, newest first. The list is not filtered — revoked and expired keys are returned alongside live ones. Read isActive and isExpired rather than assuming every row is usable.
| Field | Type | Description |
|---|---|---|
id | string | Key id — the KEY_ID path segment for reveal / details / revoke. |
keyPrefix | string | First 20 characters of the key plus a literal .... Display label, not a credential. |
name | string | The label you supplied at creation. |
permissions | string[] | read and/or write. |
isActive | boolean | false once revoked. Revocation is a flag flip; the row is never deleted. |
isExpired | boolean | Computed against expiresAt at read time. |
lastUsed | string | null | Timestamp of the last successful authentication. null if never used. |
usageCount | number | Incremented on every successful authentication. |
createdAt / expiresAt | string | ISO timestamps. |
Get Key Details
curl https://api.kolbo.ai/api/api-keys/KEY_ID \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Returns the same field set as one list row, under data. A key id that does not exist returns 404; one that exists but belongs to someone else returns 403 — unlike the reveal endpoint, which collapses both into 404.
Revoke a Key
curl -X DELETE https://api.kolbo.ai/api/api-keys/KEY_ID \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Revocation is immediate and permanent — there is no un-revoke. The key stays in the list with isActive: false.
Permission Scopes
A key carries read, write, or both.
- Safe methods (
GET,HEAD,OPTIONS) are always allowed, whatever the key's scope. - A key without
write(oradmin) is blocked on every mutating request, returning403with codeAPI_KEY_READ_ONLY. - Two paid music routes —
POST /api/v1/music-library/clean/{trackId}andPOST /api/v1/music-library/import— enforce write permission on every key, including grandfathered ones.
Scope enforcement only applies to keys minted after it was introduced. Older keys are grandfathered and can still perform writes even if their listed permissions say read only. Do not rely on an old key's read label as a security boundary — mint a fresh key if you need a genuinely read-only credential.
Limits
- Maximum 50 active keys per user (active = not revoked and not expired). Creating a 51st returns
400. - Expiration is required — every key has an
expiresAt. Default 365 days, clamped to 1–730 days. - Permissions:
readandwriteonly (admin keys cannot be self-created). - Key creation is rate limited to 10 attempts per hour per user; the reveal endpoint to 30 per minute. Both return
429.
When a Key Stops Working
An otherwise valid key is rejected when any of these are true:
| Condition | Status | Response |
|---|---|---|
Wrong prefix, unknown key, revoked, or past expiresAt | 401 | Invalid API key format / Invalid or expired API key |
| Account restricted by an administrator | 401 | User account has been restricted |
| Account soft-deleted and pending permanent deletion | 401 | Restore the account via the emailed link to reactivate existing keys |
| Email not verified | 403 | { "status": false, "message": "...", "emailNotVerified": true } |
Every 401 above shares one body — { "message": "...", "tokenExpired": false } — with no code field. The four possible messages are Invalid API key format, Invalid or expired API key, User account has been restricted, and the deletion-grace-window message. Distinguish them by reading message, not by branching on a code.
Keys are not auto-revoked during the deletion grace window, so restoring an account brings its existing keys back without re-creating them.
Security Best Practices
- Store keys in environment variables, never in code
- Use separate keys for different integrations
- Revoke unused keys promptly
- Monitor usage via the key details endpoint — every successful authentication bumps
usageCountandlastUsed