Getting Started
Install the SDK, create a client, and make your first API call in under two minutes.
Installation
# One-time: point the @kapable scope at the Kapable registry (anonymous read)
echo '@kapable:registry=https://git.kapable.dev/api/packages/kapable/npm/' >> .npmrc
bun add @kapable/sdk # or: npm install @kapable/sdk
# One-time: .cargo/config.toml (project or ~/.cargo) — anonymous read
[registries.kapable]
index = "sparse+https://git.kapable.dev/api/packages/kapable/cargo/"
# Cargo.toml
[dependencies]
kapable-sdk = { registry = "kapable", version = "0.2" }
Get a Credential
Sign up (creates your organization and a session), then mint an API key. The key's secret is returned once at creation — store it in an environment variable or secrets manager.
# 1. Sign up — org_slug is required
curl -s -X POST https://api.kapable.ai/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"...","org_name":"Acme","org_slug":"acme"}'
# → { "org_id": "...", "session_token": "kses_...", ... }
# 2. Mint an API key with the session
curl -s -X POST https://api.kapable.ai/v1/auth/api-keys \
-H "Authorization: Bearer kses_..." \
-H "Content-Type: application/json" \
-d '{"name":"my-first-key","scopes":["read"]}'
# → { "id": "...", "key_prefix": "sk_live_...", "secret": "sk_live_..." } ← shown once
A fresh sk_live_ key authenticates everywhere but is
scope-gated: the auth (/v1/me, key management),
AI (/v1/providers, proxy), and the entire
Data API
(/v1/tables, row CRUD — read scope for reads,
write for mutations/DDL, default project resolved automatically)
return 200, and /v1/board/plans works with a key — but
/v1/board/stories, /v1/board/products, and the
knowledge module still permission-gate API keys
(you'll see 403 permission required (role 'api_key' insufficient)).
For those, use a session token
(Authorization: Bearer kses_...).
Create a Client
import { KapableClient } from '@kapable/sdk';
const client = new KapableClient({
baseUrl: 'https://api.kapable.ai',
apiKey: 'sk_live_...',
});
use kapable_sdk::KapableClient;
let client = KapableClient::new("https://api.kapable.ai")
.api_key("sk_live_...")
.build();
Constructor Options
| Option | Type | Description |
|---|---|---|
baseUrl |
string |
API base URL (e.g. https://api.kapable.ai) |
apiKey |
string? |
API key for x-api-key header auth |
token |
string? |
JWT bearer token (mutually exclusive with apiKey) |
timeout |
number? |
Request timeout in ms (default: 30000) |
First API Call
The SDK exposes typed sub-clients for each service: client.auth,
client.ai, client.board, client.store,
client.data, client.comms, client.knowledge,
client.secrets, client.billing, client.wiki,
client.harbor, and client.warrant. Each method maps 1:1
to a REST endpoint. Your first call — verify the key works:
// Who am I?
const me = await client.auth.me();
console.log(`Authenticated as ${me.identity_type} in org ${me.org_id}`);
// List the AI providers your org can proxy to
const { data: providers } = await client.ai.listProviders();
for (const p of providers) {
console.log(` ${p.name}`);
}
// Who am I?
let me = client.auth().me().await?;
println!("Authenticated in org {}", me.org_id);
// List the AI providers your org can proxy to
let providers = client.ai().list_providers().await?;
for p in &providers.data {
println!(" {}", p.name);
}
Pagination
List endpoints return a ListResponse<T> with data
and total. Use limit and offset for manual
pagination, or the built-in async generators for automatic iteration.
(Board examples below need session auth or a bridged key — see the
scope note above.)
// Auto-paginate through all stories
for await (const story of client.board.paginateStories({ status: 'active' })) {
console.log(story.code, story.title);
}
// Rust SDK -- manual pagination
let mut offset = 0;
loop {
let query = ListStoriesQuery {
status: Some("active".into()),
limit: Some(50),
offset: Some(offset),
..Default::default()
};
let page = client.board().list_stories(query).await?;
for story in &page.data {
println!("{} {}", story.code, story.title);
}
offset += page.data.len() as i64;
if offset >= page.total { break; }
}
Error Handling
All SDK methods throw a KapableError on non-2xx responses.
The error includes the HTTP status, a machine-readable code, and a human message.
import { KapableError } from '@kapable/sdk';
try {
await client.board.getStory('nonexistent');
} catch (err) {
if (err instanceof KapableError) {
console.error(`${err.status} ${err.code}: ${err.message}`);
// 404 not_found: Story not found
}
}
// Rust SDK
use kapable_sdk::KapableError;
match client.board().get_story("nonexistent").await {
Ok(story) => println!("Found: {}", story.title),
Err(KapableError::Api { status, code, message }) => {
eprintln!("{status} {code}: {message}");
// 404 not_found: Story not found
}
Err(e) => eprintln!("Other error: {e}"),
}