Quickstart
Go from zero to your first authenticated Kabeen Public API call in about five minutes
Go from zero to your first authenticated call against the Kabeen Public API in about five minutes. Swap in your own API key and host and every example below is copy-pasteable as-is.
1. Prerequisites
You need:
- A Kabeen workspace.
- An API key, created by a workspace admin from inside the Kabeen app. Keys are workspace-scoped (never passed in the path or body) and carry a set of permission scopes (e.g.
applications:read,applications:add). See Authentication for how keys are issued, rotated, and scoped.
Every request is authenticated with either header — pick one and stick with it:
Authorization: Bearer kbn_live_...or
X-Api-Key: kbn_live_...Export your key and host as environment variables so every snippet below just works:
export KABEEN_API_KEY="kbn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export KABEEN_HOST="app.kabeen.io"All requests are made against:
https://{KABEEN_HOST}/public/v12. Verify your key
Before anything else, confirm the key works and see exactly what it's allowed to do. GET /me requires no specific scope — any valid key can call it.
curl -s "https://${KABEEN_HOST}/public/v1/me" \
-H "Authorization: Bearer ${KABEEN_API_KEY}"Response:
{
"workspace": {
"id": "8f0a2b1e-2b8b-4e2a-9c3e-1a2b3c4d5e6f",
"name": "Acme Corp"
},
"key": {
"id": "3c9d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"name": "CMDB sync",
"alias": "read"
},
"permissions": [
"applications:read",
"contracts:read",
"infrastructure:read"
]
}Two things worth checking before you go further:
workspaceis the workspace your key is bound to — there is no way to address a different one with the same key.permissionsis the exact list of scopes this key grants. If the call you want isn't covered by this list, you'll get a403and need a new key with a broader scope.
3. List a resource
List endpoints share the same shape across the whole API. Let's list applications (requires scope applications:read):
curl -s "https://${KABEEN_HOST}/public/v1/applications?limit=10" \
-H "Authorization: Bearer ${KABEEN_API_KEY}"{
"data": [
{
"id": "1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d",
"name": "Salesforce",
"description": "CRM platform",
"logo": "https://cdn.kabeen.io/logos/salesforce.png",
"state": "active",
"criticality": "high",
"hostingType": "saas",
"category": {
"id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
"name": "CRM"
}
}
],
"pagination": {
"limit": 10,
"offset": 0,
"total": 42
}
}The envelope is always { "data": [...], "pagination": {...} }:
data— an array of slim, list-friendly items. Fetch a single resource for the rich version — see step 4.pagination—limit(what you asked for, clamped to[1, 200]),offset(what you asked for, floored at0), andtotal(how many items match across all pages, not just this one). Incrementoffsetbylimitto walk the rest of the list. Full details in Pagination and errors.
GET /applications also accepts search, categoryId, criticality, hostingType, tag, teamId, sort, and direction as query filters — see the Endpoint reference.
4. Fetch one resource
List items are intentionally slim. Fetch a single application by id to get the full detail record — category, vendor, tags, owners, lifecycle, support/authentication info, and custom fields (requires scope applications:read):
curl -s "https://${KABEEN_HOST}/public/v1/applications/1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d" \
-H "Authorization: Bearer ${KABEEN_API_KEY}"Response (trimmed):
{
"id": "1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d",
"name": "Salesforce",
"description": "CRM platform",
"logo": "https://cdn.kabeen.io/logos/salesforce.png",
"state": "active",
"criticality": "high",
"hostingType": "saas",
"accessUrl": "https://acme.salesforce.com",
"usageActivated": true,
"desktopApplicationNames": [],
"support": { "phone": null, "email": "support@salesforce.com", "url": null },
"authentication": { "type": "login_password" },
"category": { "id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", "name": "CRM" },
"vendor": { "id": "5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b", "name": "Salesforce Inc." },
"tags": [{ "id": "tag-1", "name": "critical" }],
"owners": [],
"lifecycle": null,
"customFields": [],
"updatedAt": "2026-07-15T10:22:00Z"
}5. Create and update
Writes need the specific scope for the action, not just applications:read.
Create an application — requires scope applications:add. Only name is required:
curl -s -X POST "https://${KABEEN_HOST}/public/v1/applications" \
-H "Authorization: Bearer ${KABEEN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "Zoom"
}'The response is a slim projection of the created application:
{
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"name": "Zoom",
"description": null,
"criticality": null,
"logo": "https://cdn.kabeen.io/logos/default.png"
}Update it — requires scope applications:edit. PATCH only changes the fields you send; a JSON null is treated as "not provided", so you can't clear a field this way:
curl -s -X PATCH "https://${KABEEN_HOST}/public/v1/applications/2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f" \
-H "Authorization: Bearer ${KABEEN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"criticality": "high",
"accessUrl": "https://zoom.us"
}'The response this time is the full application detail (same shape as step 4), reflecting your change.
6. Handle errors and pagination
- Every 4xx/5xx response is the same JSON shape:
{ "code", "message", "status" }. Checkcodefor programmatic handling — it's stable across releases even ifmessagewording changes. The one exception is401, which comes back with an empty body. - The two errors you'll hit constantly while integrating:
401(bad or missing key) and403(key is valid but missing the scope the endpoint requires — re-checkpermissionsfrom step 2). - Pagination is offset-based everywhere except the audit log, which is cursor-based (
cursor/nextCursor) because it's append-only and high-volume.
Full reference: Pagination and errors.
7. The same call in three languages
Here's GET /applications?limit=10 from step 3, once in each language.
curl
curl -s "https://${KABEEN_HOST}/public/v1/applications?limit=10" \
-H "Authorization: Bearer ${KABEEN_API_KEY}"JavaScript (Node 18+, global fetch)
const host = process.env.KABEEN_HOST ?? "app.kabeen.io";
const apiKey = process.env.KABEEN_API_KEY;
const response = await fetch(`https://${host}/public/v1/applications?limit=10`, {
headers: {
Authorization: `Bearer ${apiKey}`,
},
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.message}`);
}
const { data, pagination } = await response.json();
console.log(`Got ${data.length} of ${pagination.total} applications`);Python (requests)
import os
import requests
host = os.environ.get("KABEEN_HOST", "app.kabeen.io")
api_key = os.environ["KABEEN_API_KEY"]
response = requests.get(
f"https://{host}/public/v1/applications",
headers={"Authorization": f"Bearer {api_key}"},
params={"limit": 10},
)
response.raise_for_status()
body = response.json()
print(f"Got {len(body['data'])} of {body['pagination']['total']} applications")Next steps
- Authentication — API keys, scopes, and
/mein depth. - Pagination and errors — the envelopes and the error contract.
- Endpoint reference — every endpoint with its inputs and outputs.