The official Klarora SDK for JavaScript and TypeScript. Works in Node.js and browser environments. It covers tasks, goals, team, documents, whiteboards, and forms, and authenticates with an API key.
# npm
npm install @kairos-connect/sdk
# yarn
yarn add @kairos-connect/sdk
# pnpm
pnpm add @kairos-connect/sdk
# bun
bun add @kairos-connect/sdkimport { Kairos } from '@kairos-connect/sdk';
// Initialize the client
const kairos = new Kairos({
apiKey: process.env.KAIROS_API_KEY,
});
// List tasks
const { data: tasks, pagination } = await kairos.tasks.list({
status: 'in_progress',
limit: 10,
});
console.log(`Found ${pagination.total} tasks`);
tasks.forEach(task => {
console.log(`- ${task.title} (${task.status})`);
});The SDK authenticates with an API key (kairos_sk_...). Pass it as apiKey, or omit it and set the KAIROS_API_KEY environment variable. The constructor throws if neither is set. Use kairos.me() to validate the key and see its team, scopes, and rate limits.
import { Kairos } from '@kairos-connect/sdk';
// Reads KAIROS_API_KEY from the environment
const kairos = new Kairos();
const me = await kairos.me();
console.log(me.team_id);
console.log(me.scopes.join(', '));
console.log(me.rate_limit_per_minute, me.rate_limit_per_hour);import { Kairos } from '@kairos-connect/sdk';
const kairos = new Kairos({
// API key (defaults to the KAIROS_API_KEY environment variable)
apiKey: process.env.KAIROS_API_KEY,
// Optional: Custom base URL (default: https://gateway.thekairos.app/v1)
baseUrl: 'https://gateway.thekairos.app/v1',
// Optional: Request timeout in milliseconds (default: 30000)
timeout: 60000,
// Optional: Maximum retries when rate limited (default: 3)
maxRetries: 3,
});When a request is rate limited (HTTP 429), the SDK waits for the number of seconds in the Retry-After header and retries, up to maxRetries times.
// List tasks with filters
const { data: tasks, pagination } = await kairos.tasks.list({
status: 'in_progress', // 'to_do' | 'in_progress' | 'in_review' | 'completed' | 'cancelled'
priority: 'high', // 'low' | 'medium' | 'high' | 'urgent'
assigned_to: 'user-id',
goal_id: 'goal-id',
search: 'authentication',
limit: 50,
offset: 0,
});const task = await kairos.tasks.get('task-id');
console.log(task.title, task.status);const newTask = await kairos.tasks.create({
title: 'Implement new feature',
description: 'Add user authentication',
type: 'task', // 'task' | 'sub_task' | 'bug' | 'story' | 'epic'
goal_id: 'goal-id',
priority: 'high',
due_date: '2026-12-15',
assigned_to: 'user-id',
estimated_hours: 8,
});const updatedTask = await kairos.tasks.update('task-id', {
status: 'completed',
priority: 'low',
});await kairos.tasks.delete('task-id');// Labels
const labels = await kairos.tasks.listLabels('task-id');
await kairos.tasks.addLabel('task-id', { label_id: 'label-id' });
await kairos.tasks.removeLabel('task-id', 'label-id');
// Comments
const { data: comments } = await kairos.tasks.listComments('task-id', { limit: 10 });
const comment = await kairos.tasks.addComment('task-id', { content: 'Ready for review' });
await kairos.tasks.updateComment(comment.id, { content: 'Ready for review, tests added' });
await kairos.tasks.deleteComment(comment.id);// List goals
const { data: goals } = await kairos.goals.list({
status: 'active', // 'active' | 'completed' | 'archived'
limit: 20,
});
// Create, get, update, delete
const created = await kairos.goals.create({
title: 'Q2 Product Launch',
due_date: '2026-06-30',
});
const goal = await kairos.goals.get(created.id);
await kairos.goals.update(goal.id, { status: 'completed' });
await kairos.goals.delete(goal.id);
console.log(`Goal: ${goal.title}`);
console.log(`Progress: ${goal.progress}`);
// Tasks that belong to a goal
const { data: goalTasks } = await kairos.goals.listTasks('goal-id', {
status: 'completed',
});
// Comments on a goal
const { data: goalComments } = await kairos.goals.listComments('goal-id');
await kairos.goals.addComment('goal-id', { content: 'On track' });// Get team info
const team = await kairos.team.get();
console.log(`Team: ${team.name}`);
// List team members (teamId required)
const { data: members } = await kairos.team.listMembers(team.id);
members.forEach(member => {
console.log(`${member.name} (${member.role})`);
});// List documents
const { data: docs } = await kairos.documents.list({
type: 'page', // 'document' | 'database' | 'page'
search: 'roadmap',
limit: 20,
});
// Get a document
const doc = await kairos.documents.get('doc-id');
console.log(doc.title);
console.log(doc.content); // Rich text (Prosemirror) JSON
// Create, update, delete
const created = await kairos.documents.create({ title: 'Meeting notes' });
await kairos.documents.update(created.id, { title: 'Meeting notes (final)' });
await kairos.documents.delete(created.id);// List whiteboards
const { data: boards } = await kairos.whiteboards.list({ search: 'planning' });
// Create, get, update, delete
const board = await kairos.whiteboards.create({
title: 'Sprint planning',
is_public: false,
});
const fetched = await kairos.whiteboards.get(board.id);
await kairos.whiteboards.update(board.id, { title: 'Sprint 12 planning' });
await kairos.whiteboards.delete(board.id);// List forms
const { data: forms } = await kairos.forms.list({ limit: 20 });
// Create a form
const form = await kairos.forms.create({
name: 'Contact request',
fields: [
{ id: 'email', type: 'email', label: 'Email', required: true },
{ id: 'message', type: 'textarea', label: 'Message', required: false },
],
});
// Submit a response and list submissions
await kairos.forms.submit(form.id, { email: 'jane@example.com', message: 'Hello' });
const { data: submissions } = await kairos.forms.listSubmissions(form.id);
// Get, update, delete
await kairos.forms.get(form.id);
await kairos.forms.update(form.id, { is_active: false });
await kairos.forms.delete(form.id);Every error extends KairosError. The subclasses are AuthError (401), ForbiddenError (403), NotFoundError (404), RateLimitError (429), ValidationError (400), and InternalError (500, 502, 503, 504).
import {
Kairos,
KairosError,
AuthError,
ForbiddenError,
NotFoundError,
ValidationError,
RateLimitError,
InternalError,
} from '@kairos-connect/sdk';
try {
const task = await kairos.tasks.get('invalid-id');
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Task not found');
} else if (error instanceof ValidationError) {
console.log('Validation error:', error.message);
} else if (error instanceof RateLimitError) {
console.log('Rate limited. Retry after:', error.retryAfter, 'seconds');
} else if (error instanceof AuthError) {
console.log('Authentication failed');
} else if (error instanceof KairosError) {
// code, message, statusCode and requestId are available on every error
console.log('API error:', error.code, error.statusCode, error.message, error.requestId);
}
}The SDK includes full TypeScript definitions:
import type {
Task,
Goal,
Comment,
Team,
TeamMember,
Document,
Whiteboard,
Form,
FormSubmission,
PaginatedResponse,
} from '@kairos-connect/sdk';
// All methods are fully typed
const task: Task = await kairos.tasks.get('id');
const result: PaginatedResponse<Task> = await kairos.tasks.list();
// Enumerated values are available through the model types
type TaskStatus = Task['status'];
type GoalStatus = Goal['status'];For browser usage, create a backend endpoint that proxies requests:
// Next.js API Route (pages/api/kairos/[...path].ts)
import { Kairos } from '@kairos-connect/sdk';
const kairos = new Kairos({
apiKey: process.env.KAIROS_API_KEY,
});
export default async function handler(req, res) {
// Proxy requests to Klarora API
// Add your own authentication logic here
}