AI API
Org-scoped AI provider management and a pass-through proxy: configure provider credentials once per org, then call any provider's native API through Kapable without shipping provider keys to clients.
Token tier: API keys work here
The AI module is scope-gated: an sk_live_ key with the right
scope gets 200 (verified live — it's one of the surfaces in the
SDK's golden-path smoke test).
Providers
| Method | Path | SDK (client.ai) |
|---|---|---|
| GET | /v1/providers | listProviders |
| GET | /v1/providers/{id} | getProvider |
| POST | /v1/providers/{id}/configure | configureProvider |
| DELETE | /v1/providers/{id}/configure | removeProviderConfig |
Provider proxy
POST /v1/proxy/{provider}/{path} forwards the request to the
configured provider with the org's stored credentials. The SDK returns the raw
Response so you keep full control over streaming bodies.
SDK Examples
// List providers and their configuration state
const { providers } = await client.ai.listProviders();
// Point the provider at a strongbox secret holding the org's upstream key —
// the raw key never travels through this SDK (store it via client.secrets first)
await client.ai.configureProvider('anthropic', { key_name: 'anthropic-api-key' });
// Call the provider's native API through the proxy
const res = await client.ai.proxy('anthropic', '/v1/messages', {
body: {
model: 'claude-sonnet-4-6',
max_tokens: 256,
messages: [{ role: 'user', content: 'Hello from Kapable' }],
},
});
const completion = await res.json();
let providers = client.ai().list_providers(ListProvidersParams::default()).await?;
let payload = serde_json::json!({
"model": "claude-sonnet-4-6",
"max_tokens": 256,
"messages": [{"role": "user", "content": "Hello from Kapable"}]
});
let res = client.ai().proxy("anthropic", "/v1/messages", ProxyRequest {
body: Some(serde_json::to_vec(&payload)?),
..ProxyRequest::post()
}).await?;