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 live under /api/api-keys (not /api/v1). Creating, revealing and revoking a key require an interactive sign-in: the request must be authenticated with a JWT from your browser session (Authorization: Bearer ...), which is what the Developer Console sends.
| Endpoint | JWT | X-API-Key |
|---|---|---|
POST /api/api-keys (create) | Yes | No — 403 |
GET /api/api-keys/{keyId}/reveal | Yes | No — 403 |
DELETE /api/api-keys/{keyId} (revoke) | Yes | No — 403 |
GET /api/api-keys (list) | Yes | Yes |
GET /api/api-keys/{keyId} (details) | Yes | Yes |
An API key cannot mint, reveal or revoke API keys — not even one with write permission. Those three calls made with X-API-Key return 403 with { "status": false, "code": "INTERACTIVE_AUTH_REQUIRED", "message": "Sign in to manage API key secrets." }.
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"]. A single string (e.g. "read") is accepted and wrapped into an array. Any other value returns 400 (Invalid permission: "<value>". Allowed: read, write) — 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, API key not found).
Every other failure returns 400 with a message:
message | Cause |
|---|---|
This key was created before full-reveal was supported. Create a new key to view it in full. | Key minted before the encrypted copy existed — the only fix is to create a replacement key. |
This connector credential cannot be revealed | Internal connector (OAuth) credentials, keys with source: "connector", and Developer Console USD keys (billingMode: "usd"). isRevealable only reflects the first case, so a USD or connector-source key can show isRevealable: true and still be refused. |
Unable to reveal this key | The stored copy could not be decrypted. |
Revealing a key does not require it to be active — revoked and expired keys can still be revealed, but they will not authenticate.
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. |
source | string | Where the key came from: web for keys you create here; other values (e.g. cli, desktop, connector) mark keys minted by Kolbo sign-in flows. |
credentialType | string | api_key, or oauth_connector for an internal connector credential. |
billingMode | string | credits or usd. List only — not returned by the details endpoint. |
isRevealable | boolean | false for internal connector credentials. It does not account for USD keys or connector-source keys, which the reveal endpoint also refuses — see the reveal errors above. |
The list also includes keys minted automatically by Kolbo sign-in flows (Kobi Code, the desktop app, connectors), so expect rows you did not create in the Developer Console.
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 (minus billingMode), 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"Returns { "status": true, "message": "API key revoked successfully" }. An unknown key id returns 404; a key that belongs to someone else returns 403. Requires a JWT — see the table above.
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. - A few routes enforce write permission on every key, including grandfathered ones, and return
403for a key withoutwrite:POST /api/v1/music-library/clean/{trackId}andPOST /api/v1/music-library/import(paid music; codeAPI_KEY_READ_ONLY)POST /api/v1/projects/{id}/transfer,POST /api/v1/project-transfers/{id}/accept,POST /api/v1/project-transfers/{id}/decline,DELETE /api/v1/project-transfers/{id}(codeAPI_KEY_READ_ONLY)POST /api/v1/downloads(nocode; body{ "error": "API key requires write permission" })POST /api/v1/editor/sessions,PATCH /api/v1/editor/sessionsandPOST /api/v1/editor/exports(codeFORBIDDEN)- Every Flows write and run:
POST /api/v1/flows,PATCH /api/v1/flows/{flowId},POST /api/v1/flows/{flowId}/+snapshot,undo,duplicate,move,trash,restoreorruns, andPOST /api/v1/flows/{flowId}/runs/{runId}/cancelor/retry(codeFORBIDDEN)
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
- 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
429with{ "status": false, "message": "...", "retryAfter": <seconds> }(3600for create,60for reveal).
When a Key Stops Working
An otherwise valid key is rejected when any of these are true:
| Condition | Status | Response |
|---|---|---|
No X-API-Key header and no Authorization bearer token | 401 | Unauthorized - Token missing |
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 | Account is scheduled for permanent deletion. Restore it via the link in your email to use this API key again. |
| Developer Console USD key used outside the Developer Console API | 401 | USD API key is restricted to the developer console API |
| Email not verified | 403 | { "status": false, "message": "Please verify your email to access the platform.", "emailNotVerified": true } |
| Read-only key on a mutating request | 403 | { "status": false, "message": "This API key is read-only. Create a key with write permission to perform this action.", "code": "API_KEY_READ_ONLY" } |
| Unexpected server error while validating the key | 500 | { "message": "Authentication server error", "tokenExpired": false } |
Every 401 above shares one body — { "message": "...", "tokenExpired": false } — with no code field. 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
Related
Build with Lovable, Base44 & More
Ready-to-paste prompts for Lovable, Base44, Bolt, v0 and other AI app builders. Build working apps with Kolbo API integration in one prompt.
Models & Pricing
Live model credit costs and pricing sources. Personal subscription credits have no fixed USD exchange rate; Developer USD wallet pricing is separate.