API & SDK
Build custom integrations and extend Coline with the Kairo SDK. Authenticate with OAuth 2.0, stream AI responses, and integrate Kairo into your applications.
Overview
The Kairo SDK provides:
- OAuth 2.0 authentication with PKCE and device flow support
- Streaming API for AI agent responses
- TypeScript SDKs for Node.js and browser environments
- Token management with automatic refresh
SDKs
Install the official SDK packages from npm:
# Core types and utilities
npm install @colineapp/kairo-core
# OAuth authentication helpers
npm install @colineapp/kairo-auth
# AI agent streaming client
npm install @colineapp/kairo-agent
# Kairo Code client with ACP/A2A adapter helpers
npm install @colineapp/kairo-code
# ACP CLI bridge for editors
npm install @colineapp/kairo-code-acpAll packages require Node.js 20 or later and are published under the Apache-2.0 license.
| Package | Description |
|---|---|
@colineapp/kairo-core | Core types, SSE streaming utilities, error handling |
@colineapp/kairo-auth | OAuth helpers for PKCE, token exchange, device flow, token management |
@colineapp/kairo-agent | Agent client for streaming AI responses |
@colineapp/kairo-code | Kairo Code client with native ACP/A2A adapter helpers |
@colineapp/kairo-code-acp | ACP-compatible kairo-code-acp CLI bridge for editor integrations |
Authentication
The Kairo API uses OAuth 2.0 with PKCE (required). Two authentication flows are supported:
Authorization code flow
For web applications with a redirect URI:
import {
createAuthorizationRequest,
exchangeAuthorizationCode,
createTokenManager,
MemoryTokenStorage,
} from '@colineapp/kairo-auth';
// 1. Create authorization request with PKCE
const authRequest = await createAuthorizationRequest({
clientId: 'your-client-id',
redirectUri: 'https://yourapp.com/callback',
scope: ['kairo.agent:stream', 'kairo.models:read'],
});
// 2. Redirect user to authRequest.url
// User authorizes and is redirected back with ?code=...
// 3. Exchange code for tokens
const result = await exchangeAuthorizationCode({
clientId: 'your-client-id',
redirectUri: 'https://yourapp.com/callback',
code: authorizationCode,
codeVerifier: authRequest.pkce.codeVerifier,
});
// 4. Use token manager for automatic refresh
const tokenManager = createTokenManager({
storage: new MemoryTokenStorage(),
clientId: 'your-client-id',
});
await tokenManager.setTokens(result.tokens);Device flow
For CLI tools, desktop apps, and environments without a browser redirect:
import {
startDeviceAuthorization,
pollDeviceAuthorization,
} from '@colineapp/kairo-auth';
// 1. Start device authorization
const device = await startDeviceAuthorization({
clientId: 'your-client-id',
scope: ['kairo.agent:stream', 'kairo.models:read'],
});
// 2. Display instructions to user
console.log(`Go to: ${device.verification_uri}`);
console.log(`Enter code: ${device.user_code}`);
// 3. Poll for authorization (blocks until user completes flow)
const result = await pollDeviceAuthorization({
clientId: 'your-client-id',
deviceCode: device.device_code,
intervalSeconds: device.interval,
expiresInSeconds: device.expires_in,
onPending: ({ attempt }) => {
console.log(`Waiting for authorization... (attempt ${attempt})`);
},
});
console.log('Authorized! Access token:', result.tokens.accessToken);Scopes
Request only the scopes your application needs:
| Scope | Description |
|---|---|
kairo.agent:stream | Stream AI agent responses |
kairo.code:stream | Stream code execution responses |
kairo.models:read | List available AI models |
Default scopes: kairo.agent:stream kairo.models:read
Streaming AI responses
Use the agent client to stream responses from Kairo:
import { createKairoAgent } from '@colineapp/kairo-agent';
const agent = createKairoAgent({
auth: tokenManager, // or access token string
});
// Stream with full control
const { events } = await agent.stream({
contents: [
{
role: 'user',
parts: [{ text: 'Explain how OAuth 2.0 works' }],
},
],
modelType: 'claude-opus-4.6', // optional, defaults to gpt-5.2
reasoningLevel: 1, // 0 disables thinking, >0 enables it
thinkingEffort: 'high', // Opus 4.6 only: low | medium | high | max
});
for await (const event of events) {
if (event.parsed && event.data?.candidate_content?.parts) {
for (const part of event.data.candidate_content.parts) {
if (part.text) {
process.stdout.write(part.text);
}
}
}
}
// Or use streamText for simple text accumulation
const text = await agent.streamText({
contents: [
{
role: 'user',
parts: [{ text: 'Write a haiku about APIs' }],
},
],
});
console.log(text);Claude thinking behavior
claude-opus-4.6uses adaptive thinking. SetthinkingEfforttolow,medium,high, ormax.- Opus 4.6 at
thinkingEffort: "max"has a higher usage multiplier (6x). claude-sonnet-4.5andclaude-opus-4.5usereasoningLevelas on/off (0off,1-3on) with a fixed 32k budget when enabled.thinkingBudgetis deprecated for Claude models.
Kairo Code tool behavior
POST /api/kairo/code/streamdefaultsenableToolstofalseso editor-native tools remain primary.- Set
enableTools: trueonly when you explicitly want Coline-managed tool execution for that request.
ACP / A2A adapter support
Use @colineapp/kairo-code when your host runtime is ACP/A2A-oriented:
import { createKairoCode } from '@colineapp/kairo-code';
const code = createKairoCode({ auth: tokenManager });
const { events } = await code.streamAcp({
modelId: 'claude-opus-4.6',
enableTools: false,
reasoningEnabled: true,
thinkingEffort: 'high',
messages: [
{ role: 'user', content: 'Create a README for this repo.' },
],
});
for await (const event of events) {
if (event.type === 'message_delta') {
process.stdout.write(event.text);
}
if (event.type === 'workspace_unavailable') {
console.error(event.message);
}
}streamAcp emits adapter-friendly events (message_delta, tool_call, tool_result, tool_error, workspace_unavailable, done) so integrations do not need to hand-roll bridge glue.
Use the ACP CLI bridge package when your editor expects a spawnable ACP binary:
bun add -g --no-cache @colineapp/kairo-code-acpRequired runtime env var: KAIRO_ACCESS_TOKEN
Available models
Query available models at runtime:
import { listKairoModels } from '@colineapp/kairo-core';
const { models, defaultModel } = await listKairoModels();
console.log('Default:', defaultModel);
console.log('Available:', models);Current models include: gpt-5-nano, gpt-5-mini, gpt-5, gpt-5.1, gpt-5.2, claude-opus-4.5, claude-sonnet-4.5, deepseek-v3.2, and more.
API endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/kairo/oauth/authorize | GET | OAuth authorization |
/api/kairo/oauth/token | POST | Token exchange and refresh |
/api/kairo/oauth/device/authorize | POST | Start device flow |
/api/kairo/oauth/revoke | POST | Revoke tokens |
/api/kairo/agent/stream | POST | Stream AI agent responses |
/api/kairo/code/stream | POST | Stream code execution |
/api/kairo/models | GET | List available models |
Base URL: https://coline.app
Token management
The SDK includes a token manager that handles refresh automatically:
import {
createTokenManager,
MemoryTokenStorage,
} from '@colineapp/kairo-auth';
const tokenManager = createTokenManager({
storage: new MemoryTokenStorage(), // or implement KairoTokenStorage
clientId: 'your-client-id',
minValidityMs: 30000, // refresh 30s before expiry
});
// Get a valid access token (refreshes automatically if needed)
const accessToken = await tokenManager.getAccessToken();
// Manually refresh
await tokenManager.refresh();
// Clear stored tokens
await tokenManager.clear();Implement KairoTokenStorage interface for persistent storage:
interface KairoTokenStorage {
getTokens(): Promise<KairoTokenSet | null> | KairoTokenSet | null;
setTokens(tokens: KairoTokenSet | null): Promise<void> | void;
}Token specifications
| Token | Lifetime |
|---|---|
| Access token | 60 minutes |
| Refresh token | 30 days |
| Authorization code | 10 minutes |
| Device code | 15 minutes |
Tokens are automatically rotated on refresh.
Error handling
The SDK throws KairoError for API and authentication errors:
import { KairoError } from '@colineapp/kairo-core';
try {
const { events } = await agent.stream({ contents: [...] });
} catch (error) {
if (error instanceof KairoError) {
console.error('Code:', error.code);
console.error('Message:', error.message);
console.error('Status:', error.status);
console.error('Details:', error.details);
}
}Common error codes:
| Code | Description |
|---|---|
missing_access_token | No token provided |
expired_token | Token has expired |
invalid_grant | Invalid or revoked refresh token |
missing_refresh_token | Refresh token not available |
authorization_pending | Device flow waiting for user |
Resources
- Documentation: coline.app/developers/docs/kairo
- GitHub: github.com/ColineApp/coline
- Issues: github.com/ColineApp/coline/issues
Tips
- Use the token manager instead of handling tokens manually. It refreshes automatically before expiry.
- Start with device flow for CLI tools and scripts. It is simpler than setting up redirect URIs.
- Request minimal scopes. Only request what your application needs.
- Handle streaming errors gracefully. Network interruptions can occur during long-running streams.
- Cache the model list if you display model options. It does not change frequently.