@kaiban/sdk
v0.3.1
Published
Official TypeScript SDK for the Kaiban API
Readme
Kaiban TypeScript SDK
Official TypeScript SDK for the Kaiban API.
Install
npm install @kaiban/sdkQuickstart
import { createKaibanClient } from '@kaiban/sdk';
const client = createKaibanClient({
tenant: 'your-tenant',
token: process.env.KAIBAN_TOKEN,
});
const result = await client.agents.list({ limit: 10 });
console.log(result.data); // Array of agentsAuth and Tenancy
- Uses
Authorization: Bearer <token>automatically when provided - Sends
x-tenantheader with the configured tenant - Default base URL:
https://{tenant}.kaiban.io - Custom base URL can be configured via
baseUrloption
Resources
The SDK provides clients for the following API resources:
Available Resource Clients
- agents:
list,listAll,get,create,update,createFeedback,listSupervisorFeedback - teamMembers:
list,listAll,get - cards:
list,listAll,get,create,update,delete,moveToColumn,createActivity,createBatchActivities,listActivities,listAllActivities - activities:
list,listAll,create,createBatch - teams:
list,listAll,get - boards:
list,listAll,get,create - resources:
list,listAll,get - external_channels:
list,listAll,get - costs:
calculateCosts(offline utility for model cost calculations)
Pagination
All list methods return paginated results with cursor-based navigation:
import { type Paginated, type Agent, type Card, type ListParams } from '@kaiban/sdk';
// Basic pagination
const params: ListParams = {
limit: 10,
order_by: '-created_at',
filters: { status: 'active' },
};
const result: Paginated<Agent> = await client.agents.list(params);
console.log(result.data); // Array of Agent objects
console.log(result.pagination.next_cursor); // Cursor for next page
console.log(result.pagination.prev_cursor); // Cursor for previous page
// Navigate to next page
if (result.pagination.next_cursor) {
const nextPage = await client.agents.list({
limit: 10,
after: result.pagination.next_cursor,
});
}
// Navigate backwards
if (result.pagination.prev_cursor) {
const prevPage = await client.agents.list({
limit: 10,
before: result.pagination.prev_cursor,
});
}
// Filter cards by metadata (cards only)
const cardsResult: Paginated<Card> = await client.cards.list({
limit: 20,
metadata: { thread_id: 'thread-123', user_id: 'user-456' },
});
// This becomes: ?metadata.thread_id=thread-123&metadata.user_id=user-456All listAll methods return async generators that automatically handle pagination:
// Iterate through all items automatically
for await (const agent of client.agents.listAll({ limit: 100 })) {
console.log(agent.id, agent.name);
}Types
All types are published and re-exported from @kaiban/sdk. Available types include:
- Entities:
Agent,Card,Activity,Team,Board,Resource,ExternalChannel,TeamMember,Column - Agent Types:
AgentFeedback,AgentSupervisorFeedback,AgentType,AgentStatus,AgentFeedbackStatus,AgentFeedbackType,AgentFeedbackEvaluation - Activity Types:
ActivityCreate,ActivityActor,ActivityChange,ActivityType - Card Types:
CardStatus,CardPart - Board Types:
Column - Resource Types:
ResourceStatus - External Channel Types:
ExternalChannelType,ExternalChannelStatus,ExternalChannelPriority - Cost Types:
ModelCostInput,ModelCostOutput - A2A Data Parts:
A2ADataPartType,ToolCallStartPart,ToolCallArgsPart,ToolCallEndPart,ToolCallResultPart,TaskInfoMessagePart,TaskStepOutputPart,UserEvaluationPart,UserThreadFeedbackPart,UserCloseThreadPart,GenerateReportPart,KaibanActivityPart,AgentStatusPart - Request/Response:
ListParams,Paginated,PaginationMeta - Configuration:
KaibanClientConfig,RequestOptions - Shared Types:
ISODate - Error classes:
HttpError,ApiError,BadRequestError,ValidationError,UnauthorizedError,ForbiddenError,NotFoundError,ConflictError,RateLimitError,UnavailableError,ServerError,TimeoutError,AbortedError
Example: Using Types
import {
createKaibanClient,
type Agent,
type Card,
type Activity,
type ActivityCreate,
type Paginated,
type ListParams,
CardStatus,
ActivityType,
} from '@kaiban/sdk';
const client = createKaibanClient({
tenant: 'my-tenant',
token: process.env.KAIBAN_TOKEN!,
});
// Type-safe card creation
// Use Omit<Card, 'id' | 'created_at'> for the input type
const cardData: Omit<Card, 'id' | 'created_at'> = {
team_id: 'team-123',
board_id: 'board-123',
owner_id: 'user-123',
agent_id: 'agent-123',
title: 'New task',
status: CardStatus.BACKLOG,
column_key: 'inbox',
priority: 'high',
member_ids: [],
};
const card: Card = await client.cards.create(cardData);
// Type-safe card update
// Use Partial<Omit<Card, 'id' | 'created_at' | 'updated_at'>>
const updateData: Partial<Omit<Card, 'id' | 'created_at' | 'updated_at'>> = {
status: CardStatus.DOING,
priority: 'urgent',
};
const updatedCard: Card = await client.cards.update(card.id, updateData);
// Type-safe activity creation
const activityData: ActivityCreate = {
board_id: card.board_id,
team_id: card.team_id,
card_id: card.id,
type: ActivityType.CARD_COMMENT_ADDED,
description: 'Initial comment',
actor: { id: 'user-1', type: 'user', name: 'John' },
};
const activity: Activity = await client.activities.create(activityData);Documentation
The SDK includes comprehensive JSDoc documentation for all client methods and types.
Generate Documentation
To generate the full API documentation:
npm run docs:generateThis will create a docs folder with HTML documentation that you can open in your browser.
Build Documentation
To clean and rebuild the documentation from scratch:
npm run docs:buildServe Documentation Locally
To generate and serve the documentation locally:
npm run docs:serveThis will generate the docs and start a local server (requires npx serve to be available).
Clean Documentation
To remove the generated documentation:
npm run docs:cleanConfiguration
The client accepts the following configuration options:
import { createKaibanClient, type KaibanClientConfig } from '@kaiban/sdk';
const config: KaibanClientConfig = {
tenant: 'your-tenant', // Required: Your tenant identifier
token: 'your-api-token', // Required: Your API authentication token
baseUrl: 'https://custom-host', // Optional: Custom API base URL (default: https://{tenant}.kaiban.io)
timeoutMs: 30000, // Optional: Request timeout in milliseconds (default: 30000)
retry: {
// Optional: Retry configuration
maxAttempts: 3, // Maximum number of retry attempts (default: 3)
backoffMs: 1000, // Initial backoff delay in ms (default: 1000)
maxBackoffMs: 30000, // Maximum backoff delay in ms (default: 30000)
jitter: true, // Add randomness to backoff (default: true)
retryOn: [429, 502, 503, 504], // Optional: HTTP status codes to retry on
retryMethods: ['GET', 'PUT', 'DELETE'], // Optional: HTTP methods to retry
},
fetch: globalThis.fetch, // Optional: Custom fetch implementation
onRequest: ({ method, url, init }) => {
// Optional: Hook called before each request
console.log(`Making ${method} request to ${url}`);
},
onResponse: ({ status, url, response }) => {
// Optional: Hook called after each response
console.log(`Received ${status} from ${url}`);
},
};
const client = createKaibanClient(config);
// You can also update the token dynamically after client creation
client.setToken('new-token'); // Set a new token
client.setToken(); // Clear the tokenPer-call Options
All resource methods accept an optional RequestOptions parameter for per-call overrides:
import { type RequestOptions } from '@kaiban/sdk';
const options: RequestOptions = {
headers: { 'x-request-id': 'abc-123' }, // Custom headers
timeoutMs: 10_000, // Override timeout for this request
signal: new AbortController().signal, // AbortSignal for cancellation
retry: {
// Override retry behavior
maxAttempts: 5,
},
};
await client.cards.list({ limit: 20 }, options);
await client.agents.get('agent-123', options);Error Handling
The SDK provides typed error classes for different HTTP status codes and network errors:
import {
createKaibanClient,
ApiError,
NotFoundError,
BadRequestError,
ValidationError,
UnauthorizedError,
RateLimitError,
BadGatewayError,
GatewayTimeoutError,
UnavailableError,
TimeoutError,
AbortedError,
} from '@kaiban/sdk';
const client = createKaibanClient({
tenant: 'your-tenant',
token: process.env.KAIBAN_TOKEN!,
});
try {
await client.cards.get('non-existent-id');
} catch (err) {
if (err instanceof NotFoundError) {
console.error('Card not found:', err.message);
console.error('Error code:', err.code); // 'not_found'
console.error('Request ID:', err.meta?.request_id);
console.error('Timestamp:', err.meta?.timestamp);
} else if (err instanceof ValidationError) {
console.error('Validation failed:', err.message);
console.error('Error code:', err.code); // 'validation_error'
// ValidationError.details includes issues array
if (err.details?.issues) {
err.details.issues.forEach((issue) => {
console.error(` - ${issue.path.join('.')}: ${issue.message}`);
});
}
} else if (err instanceof BadRequestError) {
console.error('Invalid request:', err.message);
console.error('Error code:', err.code); // 'invalid_argument'
} else if (err instanceof UnauthorizedError) {
console.error('Authentication required:', err.message);
console.error('Error code:', err.code); // 'unauthenticated'
} else if (err instanceof RateLimitError) {
console.error('Rate limit exceeded:', err.message);
console.error('Error code:', err.code); // 'rate_limit_exceeded'
} else if (err instanceof BadGatewayError) {
console.error('Bad gateway:', err.message);
console.error('Error code:', err.code); // 'bad_gateway'
} else if (err instanceof GatewayTimeoutError) {
console.error('Gateway timeout:', err.message);
console.error('Error code:', err.code); // 'gateway_timeout'
} else if (err instanceof UnavailableError) {
console.error('Service unavailable:', err.message);
console.error('Error code:', err.code); // 'service_unavailable'
} else if (err instanceof TimeoutError) {
console.error('Request timed out');
} else if (err instanceof AbortedError) {
console.error('Request was cancelled');
} else if (err instanceof ApiError) {
console.error('API error:', err.message);
console.error('Error code:', err.code);
console.error('Details:', err.details);
} else {
console.error('Unexpected error:', err);
}
}Available Error Classes
ApiError: Base class for all API errors (includescode,message,details,metaproperties)BadRequestError: 400 - Invalid request format or parameters (invalid_argument)ValidationError: 422 - Request validation failed (validation_error, includesdetails.issues[])UnauthorizedError: 401 - Authentication required or failed (unauthenticated)ForbiddenError: 403 - Insufficient permissions (permission_denied)NotFoundError: 404 - Resource not found (not_found)ConflictError: 409 - Resource conflict (conflict)RateLimitError: 429 - Too many requests (rate_limit_exceeded)BadGatewayError: 502 - Bad gateway (bad_gateway)UnavailableError: 503 - Service temporarily unavailable (service_unavailable)GatewayTimeoutError: 504 - Gateway timeout (gateway_timeout)ServerError: 500 - Internal server error (internal)TimeoutError: Request exceeded configured timeoutAbortedError: Request was cancelled via AbortSignalHttpError: Low-level HTTP error (includesstatus,url,bodyproperties)
All API errors include:
code: Backend error code (e.g.,validation_error,not_found)message: Human-readable error messagedetails: Optional error details (forValidationError, includesissues[]array)meta: Request metadata withrequest_id?andtimestamp
Examples by resource
Agents
// List agents with pagination
const result = await client.agents.list({
limit: 20,
order_by: '-created_at',
});
console.log(result.data); // Array of agents
console.log(result.pagination.next_cursor);
// Iterate through all agents
for await (const agent of client.agents.listAll({ limit: 100 })) {
console.log(agent.id, agent.name);
}
// Get agent by id
const agent = await client.agents.get('agent-123');
// Create a new agent
const newAgent = await client.agents.create({
name: 'SupportAgent',
description: 'Handles support tickets',
team_id: 'team_123',
owner_id: 'user_123',
created_by: 'user_123',
type: 'a2a',
status: 'active',
monthly_budget: 200,
examples: [],
});
// Update agent
const updated = await client.agents.update('agent-123', {
name: 'Updated Name',
description: 'New description',
});
// Create agent feedback
await client.agents.createFeedback('agent-123', {
team_id: 'team-123',
activity_id: 'activity-456',
status: 'unprocessed',
type: 'user_conversation_feedback',
evaluation: 'positive',
comment: 'Excellent performance',
created_by: 'user-001',
});
// List supervisor feedback for an agent
const feedback = await client.agents.listSupervisorFeedback('agent-123', {
limit: 10,
order_by: '-created_at',
});Teams
// List teams with pagination
const result = await client.teams.list({
limit: 20,
filters: { status: 'active' },
});
// Iterate through all teams
for await (const team of client.teams.listAll()) {
console.log(team.id, team.name);
}
// Get a specific team
const team = await client.teams.get('team-123');Team Members
// List team members with pagination
const result = await client.teamMembers.list({
limit: 20,
order_by: '-joined_at',
});
// Iterate through all team members
for await (const member of client.teamMembers.listAll({ limit: 100 })) {
console.log(member.id, member.user_id, member.role);
}
// Get a specific team member
const member = await client.teamMembers.get('tm-123');Boards
// List boards
const result = await client.boards.list({ limit: 10 });
// Iterate through all boards
for await (const board of client.boards.listAll()) {
console.log(board.id, board.name, board.columns);
}
// Get a specific board
const board = await client.boards.get('board-123');
// Create a new board
const newBoard = await client.boards.create({
name: 'Sales',
team_id: 'team_123',
owner_id: 'user_123',
created_by: 'user_123',
description: 'Manage pipeline',
columns: [],
// agent_ids, member_ids, and allowed_roles are optional (default to [])
});Cards
import { CardStatus, ActivityType } from '@kaiban/sdk';
// List cards with pagination and filters
const result = await client.cards.list({
limit: 20,
filters: { status: 'doing', board_id: 'board-123' },
order_by: '-created_at',
});
// Iterate through all cards
for await (const card of client.cards.listAll({ limit: 100 })) {
console.log(card.id, card.title);
}
// Create a card with optional activity tracking
const newCard = await client.cards.create(
{
team_id: 'team-123',
board_id: 'board-123',
owner_id: 'user-123',
agent_id: 'agent-123',
title: 'Investigate issue',
status: CardStatus.BACKLOG,
column_key: 'inbox',
priority: 'medium',
member_ids: [],
},
{ create_activity: true } // Automatically creates a 'card_created' activity
);
// Get a card
const card = await client.cards.get(newCard.id);
// Update a card
const updatedCard = await client.cards.update(card.id, {
status: CardStatus.DOING,
priority: 'high',
});
// Move card to a different column (with automatic activity tracking)
const movedCard = await client.cards.moveToColumn(card.id, 'in_progress', {
actor: {
id: 'user-123',
type: 'user',
name: 'John Doe',
},
});
// Delete a card
await client.cards.delete(card.id);
// Create an activity for a card
await client.cards.createActivity(card.id, {
board_id: card.board_id,
team_id: card.team_id,
type: ActivityType.CARD_COMMENT_ADDED,
description: 'Added a comment',
actor: { id: 'user-1', type: 'user', name: 'Alice' },
});
// Create multiple activities in batch
await client.cards.createBatchActivities(card.id, [
{
board_id: card.board_id,
team_id: card.team_id,
type: ActivityType.CARD_COMMENT_ADDED,
description: 'First comment',
actor: { id: 'user-1', type: 'user', name: 'Alice' },
},
{
board_id: card.board_id,
team_id: card.team_id,
type: ActivityType.CARD_PRIORITY_CHANGED,
description: 'Changed priority',
actor: { id: 'user-1', type: 'user', name: 'Alice' },
changes: [{ field: 'priority', old_value: 'medium', new_value: 'high' }],
},
]);
// List activities for a card
const activities = await client.cards.listActivities(card.id, {
limit: 50,
order_by: '-created_at',
});
// Iterate through all activities for a card
for await (const activity of client.cards.listAllActivities(card.id, { limit: 100 })) {
console.log(activity.type, activity.description);
}Activities
import { ActivityType, type ActivityCreate } from '@kaiban/sdk';
// List all activities with filters
const result = await client.activities.list({
limit: 50,
filters: { card_id: 'card-123' },
order_by: '-created_at',
});
// Iterate through all activities
for await (const activity of client.activities.listAll({ limit: 100 })) {
console.log(activity.id, activity.type);
}
// Create a single activity
await client.activities.create({
board_id: 'board-123',
team_id: 'team-123',
card_id: 'card-123',
type: ActivityType.CARD_PRIORITY_CHANGED,
description: 'Updated priority',
actor: { id: 'user-1', type: 'user', name: 'Alice' },
changes: [{ field: 'priority', old_value: 'low', new_value: 'high' }],
});
// Create multiple activities in batch
await client.activities.createBatch([
{
board_id: 'board-123',
team_id: 'team-123',
card_id: 'card-123',
type: ActivityType.CARD_COMMENT_ADDED,
description: 'First comment',
actor: { id: 'user-1', type: 'user', name: 'Alice' },
},
{
board_id: 'board-123',
team_id: 'team-123',
card_id: 'card-123',
type: ActivityType.CARD_COMMENT_ADDED,
description: 'Second comment',
actor: { id: 'user-2', type: 'user', name: 'Bob' },
},
]);Resources
// List resources
const result = await client.resources.list({
limit: 25,
order_by: '-created_at',
});
// Iterate through all resources
for await (const resource of client.resources.listAll()) {
console.log(resource.id, resource.title, resource.status);
}
// Get a specific resource
const resource = await client.resources.get('resource-123');External Channels
// List external channels
const result = await client.external_channels.list({ limit: 15 });
// Iterate through all channels
for await (const channel of client.external_channels.listAll()) {
console.log(channel.id, channel.type, channel.name);
}
// Get a specific channel
const channel = await client.external_channels.get('channel-123');Model Costs
The costs client provides an offline utility to calculate costs for LLM usage based on token counts:
import { type ModelCostInput } from '@kaiban/sdk';
// Calculate costs for multiple model usages
const usages: ModelCostInput[] = [
{
model: 'gpt-4o',
inputTokens: 1500,
outputTokens: 500,
reasoningTokens: 200, // Optional: reasoning tokens for models that support it
},
{
model: 'gpt-4o-mini',
inputTokens: 3000,
outputTokens: 1000,
},
];
const result = client.costs.calculateCosts(usages);
console.log('Total cost:', result.totalCost); // Total cost in dollars
console.log('Total tokens:', result.totalTokens); // Total tokens used
// Get detailed costs per model
result.costsByModel.forEach((modelCost) => {
console.log(`Model: ${modelCost.model}`);
console.log(` Input tokens: ${modelCost.inputTokens}`);
console.log(` Output tokens: ${modelCost.outputTokens}`);
console.log(` Reasoning tokens: ${modelCost.reasoningTokens}`);
console.log(` Charged output tokens: ${modelCost.chargedOutputTokens}`); // output + reasoning
console.log(` Total tokens: ${modelCost.totalTokens}`);
console.log(` Input cost: $${modelCost.inputCost.toFixed(6)}`);
console.log(` Output cost: $${modelCost.outputCost.toFixed(6)}`);
console.log(` Total cost: $${modelCost.totalCost.toFixed(6)}`);
});Supported models and their pricing (per 1M tokens):
- gpt-4o: $5.00 input, $20.00 output
- gpt-4o-mini: $0.60 input, $2.40 output
- gpt-5: $1.50 input, $10.00 output
- gpt-5-mini: $0.25 input, $2.00 output
- gpt-5-nano: $0.05 input, $0.40 output
- text-embedding-3-small: $0.02 input, $0.00 output
Note: Reasoning tokens (when provided) are billed as output tokens.
