Authentication
Kapable supports two customer authentication methods: API keys for server-to-server calls and session/JWT bearer tokens for user-context requests. Operator surfaces use a separate token tier and a separate SDK — see Operator SDK.
Token Types
| Token | Tier | Header | Use |
|---|---|---|---|
sk_live_* / sk_test_* / sk_org_* | Customer | x-api-key | Server-to-server, org-bound, scoped (read/write/admin) |
kses_* (session) | Customer | Authorization: Bearer | User-context calls; carries the member's role permissions |
| RS256 JWT | Customer | Authorization: Bearer | Frontend/user flows via the auth service |
st_* / sk_admin_* | Operator | varies | Platform operations — only via @kapable/ops-sdk, never the customer SDK |
API Key Authentication
API keys are the simplest way to authenticate. Pass the key in the
x-api-key header on every request.
# API key auth
curl https://api.kapable.ai/v1/me \
-H "x-api-key: sk_live_abc123..."
Getting an API Key
Mint keys with your session via the auth API (a console UI for key management is on the roadmap):
curl -s -X POST https://api.kapable.ai/v1/auth/api-keys \
-H "Authorization: Bearer kses_..." \
-H "Content-Type: application/json" \
-d '{"name":"production","scopes":["read","write"]}'
# → { "id": "...", "key_prefix": "sk_live_...", "secret": "sk_live_..." } ← secret shown ONCE
# List (prefixes only) and revoke:
curl -s https://api.kapable.ai/v1/auth/api-keys -H "Authorization: Bearer kses_..."
curl -s -X DELETE https://api.kapable.ai/v1/auth/api-keys/{id} -H "Authorization: Bearer kses_..."
An API key is bound to your org and carries scopes
(read/write/admin), not your member
role's permissions. Scope-gated surfaces (auth, AI, the
Data API, some board routes) accept keys
directly; permission-gated surfaces (board stories, knowledge) return
403 permission required for keys — use session auth there.
A key may optionally be bound to a project at mint time
({"project_id":"…"}) to pin its Data-API schema. Never expose
keys in client-side code or commit them to version control.
SDK Usage
const client = new KapableClient({
baseUrl: 'https://api.kapable.ai',
apiKey: process.env.KAPABLE_API_KEY,
});
// Rust SDK
let client = KapableClient::new("https://api.kapable.ai")
.api_key(std::env::var("KAPABLE_API_KEY").unwrap())
.build();
JWT Bearer Token
For user-context requests (e.g. from a frontend), use a JWT token obtained
via the Auth service's login endpoint. Pass it in the Authorization
header.
# Bearer token auth
curl https://api.kapable.ai/v1/board/stories \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Obtaining a Token
// Login. Response fields: session_token, access_token (JWT),
// access_token_expires_in, role, org_id, member_id, email, name.
const res = await client.auth.login({
email: 'user@example.com',
password: '...',
});
// Use the session token (kses_) as the Bearer `token` for subsequent requests.
const authedClient = new KapableClient({
baseUrl: 'https://api.kapable.ai',
token: res.session_token,
});
// Rust SDK
use kapable_sdk::auth::types::LoginRequest;
let resp = client.auth().login(&LoginRequest {
email: "user@example.com".into(),
password: "...".into(),
}).await?;
let authed_client = KapableClient::new("https://api.kapable.ai")
.token(resp.token)
.build();
Org Context
All API calls are scoped to the authenticated org. API keys are org-bound. JWT tokens carry the org ID in the token claims. Multi-org users select their active org during login.
Agent Keys (Comms)
The Comms service supports a third auth model: agent keys.
These are per-agent API keys minted via
POST /v1/agents/{id}/keys that allow agent processes to
authenticate directly for SSE streaming and message sending.
// Mint an agent key
const { key } = await client.comms.mintAgentKey(agentId, {
label: 'production',
});
// Use it to connect the agent's SSE stream
const stream = new EventSource(
`https://api.kapable.ai/v1/agents/${agentId}/stream`,
{ headers: { 'x-api-key': key } }
);
// Rust SDK
use kapable_sdk::comms::types::MintAgentKeyRequest;
let resp = client.comms().mint_agent_key(agent_id, MintAgentKeyRequest {
label: "production".into(),
}).await?;
println!("Agent key: {}", resp.key);
App Tokens (Comms)
For service-to-service integration with the Comms internal endpoints, use app tokens. These are org-scoped tokens for programmatic access to intercept and send operations.
// Mint an app token for your integration
const { token } = await client.comms.mintAppToken(orgId, {
label: 'email-worker',
});
// Rust SDK
use kapable_sdk::comms::types::MintAppTokenRequest;
let resp = client.comms().mint_app_token(org_id, MintAppTokenRequest {
label: "email-worker".into(),
}).await?;
Error Responses
Authentication failures return 401 Unauthorized. Two envelope
variants exist across services — handle both (the SDKs normalize them
into KapableError for you):
// Most services (data, board, knowledge, ai, ...):
{ "error": { "code": "UNAUTHORIZED", "message": "missing auth token" } }
// Auth service (flat variant):
{ "error": "UNAUTHORIZED", "message": "authentication required via x-api-key, Authorization: Bearer, or session cookie" }