Getting Started

One binary, one credential, the whole platform. Install the CLI, authenticate once, and everything works — or drop down to the SDK / REST layer it rides on.

Fastest path: the CLI

# Install (detects OS/arch, verifies SHA-256, no sudo)
curl -fsSL https://cli.kapable.ai/install.sh | sh

# Authenticate once — persisted to ~/.kapable/kapable.toml (owner-only)
kapable auth login --email you@example.com   # prompts for your password
# or, for agents / CI: persist a durable org key
kapable auth set-key sk_org_...

# Everything is now authed
kapable auth me

The CLI stays current on its own (kapable self-update). Full command tour, credential precedence, and agent-provisioning notes: CLI guide.

The browser path: zero to a live app

No CLI, no API key — the whole loop works from the browser:

  1. Sign up. From kapable.ai, click Start building. The signup form asks for a name, email, and password; you're provisioned and signed in immediately (no email-verification step).
  2. Land on the Launchpad at https://{org}.kapable.ai/ — the hub of platform tiles: Wiki, Console, Design, Knowledge, Board, Chat, Apps, and more. Click Console.
  3. Create an app. In the console sidebar, Apps+ New app. Pick a name (2–30 characters; letters, numbers, hyphens) and a starter template.
  4. Scaffolding takes 15–30 seconds: a Git repo is provisioned under your org on git.kapable.dev, the build pipeline is wired up, and the template's files are committed. You can navigate away — it continues in the background.
  5. Deploy. On the app detail page, click Deploy now. Status streams into the deployment-history card in real time.
  6. Live. Your app serves at https://{app}.{org}.kapable.run — e.g. hello-kapable.acme.kapable.run. The very first load may take ~10 seconds while the TLS certificate is issued; after that it's cached.

The app detail page also gives you the git clone URL, so you can switch to pushing code and let CI deploy from there — see Apps & Deployment for the full lifecycle and Deployments for how builds work.

The programmatic layer: SDK installation

The CLI wraps the same customer API the SDKs expose. Building an app or integration? Use the SDK directly:

# 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
What an API key can reach today

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}"),
}

Next Steps