npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@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/sdk

Quickstart

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 agents

Auth and Tenancy

  • Uses Authorization: Bearer <token> automatically when provided
  • Sends x-tenant header with the configured tenant
  • Default base URL: https://{tenant}.kaiban.io
  • Custom base URL can be configured via baseUrl option

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-456

All 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:generate

This 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:build

Serve Documentation Locally

To generate and serve the documentation locally:

npm run docs:serve

This 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:clean

Configuration

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 token

Per-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 (includes code, message, details, meta properties)
  • BadRequestError: 400 - Invalid request format or parameters (invalid_argument)
  • ValidationError: 422 - Request validation failed (validation_error, includes details.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 timeout
  • AbortedError: Request was cancelled via AbortSignal
  • HttpError: Low-level HTTP error (includes status, url, body properties)

All API errors include:

  • code: Backend error code (e.g., validation_error, not_found)
  • message: Human-readable error message
  • details: Optional error details (for ValidationError, includes issues[] array)
  • meta: Request metadata with request_id? and timestamp

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.