Board API

Work tracking orchestration -- stories, sprints, plans, products, comments, and sprint closures. Full lifecycle management from backlog to release.

Stories

Stories are the core work item. Each story has a status, optional sprint attachment, and code identifier.

MethodPathDescription
GET /v1/board/stories List stories with optional filters (status, sprint, search)
POST /v1/board/stories Create a new story
GET /v1/board/stories/{id_or_code} Get a story by UUID or code
PATCH /v1/board/stories/{id_or_code} Update a story (partial update)
DELETE /v1/board/stories/{id_or_code} Delete a story
POST /v1/board/stories/{id_or_code}/transition Transition a story to a new status

SDK Examples

// List active stories
const { data, total } = await client.board.listStories({
  status: 'active',
  limit: 25,
});

// Create a story
const story = await client.board.createStory({
  title: 'Implement user dashboard',
  description: 'Build the main dashboard view with metrics',
  status: 'backlog',
});

// Update a story
await client.board.updateStory('PROJ-42', {
  title: 'Updated title',
  description: 'Updated description',
});

// Transition to "in_progress"
const result = await client.board.transitionStory('PROJ-42', {
  to: 'in_progress',
});

// Delete a story
await client.board.deleteStory('PROJ-42');

// Auto-paginate through all stories
for await (const story of client.board.paginateStories({ status: 'done' })) {
  console.log(story.code, story.title);
}
// Rust SDK
use kapable_sdk::board::types::*;

let stories = client.board().list_stories(ListStoriesQuery {
    status: Some("active".into()),
    limit: Some(25),
    ..Default::default()
}).await?;

let story = client.board().create_story(CreateStoryRequest {
    title: "Implement user dashboard".into(),
    description: Some("Build the main dashboard view with metrics".into()),
    status: Some("backlog".into()),
    ..Default::default()
}).await?;

client.board().update_story("PROJ-42", UpdateStoryRequest {
    title: Some("Updated title".into()),
    description: Some("Updated description".into()),
    ..Default::default()
}).await?;

client.board().transition_story("PROJ-42", TransitionRequest {
    to: "in_progress".into(),
}).await?;

client.board().delete_story("PROJ-42").await?;

Sprints

Sprints group stories into time-boxed iterations. A sprint progresses through planned → active → completed states.

MethodPathDescription
GET /v1/board/sprints List sprints with optional filters
POST /v1/board/sprints Create a sprint
GET /v1/board/sprints/{id_or_code} Get a sprint (includes attached stories)
POST /v1/board/sprints/{id_or_code}/start Start a planned sprint
POST /v1/board/sprints/{id_or_code}/complete Complete an active sprint
POST /v1/board/sprints/{id_or_code}/stories Attach a story to a sprint
DELETE /v1/board/sprints/{id_or_code}/stories/{story_id} Detach a story from a sprint

SDK Examples

// Create a sprint
const sprint = await client.board.createSprint({
  name: 'Sprint 12',
  goal: 'Ship user dashboard',
  starts_at: '2026-05-20T00:00:00Z',
  ends_at: '2026-06-03T00:00:00Z',
});

// Start the sprint
await client.board.startSprint(sprint.id);

// Attach a story
await client.board.attachStory(sprint.id, {
  story_id: storyId,
});

// Complete the sprint
await client.board.completeSprint(sprint.id);
// Rust SDK
let sprint = client.board().create_sprint(CreateSprintRequest {
    name: "Sprint 12".into(),
    goal: Some("Ship user dashboard".into()),
    starts_at: Some("2026-05-20T00:00:00Z".into()),
    ends_at: Some("2026-06-03T00:00:00Z".into()),
    ..Default::default()
}).await?;

client.board().start_sprint(&sprint.id.to_string()).await?;

client.board().attach_story(&sprint.id.to_string(), AttachStoryRequest {
    story_id: story_id,
}).await?;

client.board().complete_sprint(&sprint.id.to_string()).await?;

Sprint Closures

Closures capture retrospectives and release notes when a sprint completes.

MethodPathDescription
GET /v1/board/sprints/{id_or_code}/closure Get closure for a sprint
POST /v1/board/sprints/{id_or_code}/closure Create or update a sprint closure

SDK Examples

// Upsert a sprint closure
const closure = await client.board.upsertClosure('sprint-12', {
  retro: 'Good velocity, need better estimation',
  release_notes: '## Dashboard v1\n- User metrics\n- Activity feed',
});

// Read it back
const existing = await client.board.getClosure('sprint-12');
// Rust SDK
let closure = client.board().upsert_closure("sprint-12", UpsertClosureRequest {
    retro: Some("Good velocity, need better estimation".into()),
    release_notes: Some("## Dashboard v1\n- User metrics\n- Activity feed".into()),
    ..Default::default()
}).await?;

let existing = client.board().get_closure("sprint-12").await?;

Plans

Plans are versioned documents (roadmaps, specs, designs) with revision history.

MethodPathDescription
GET /v1/board/plans List plans
POST /v1/board/plans Create a plan
GET /v1/board/plans/{id_or_code} Get a plan by UUID or code
PATCH /v1/board/plans/{id_or_code} Update a plan
GET /v1/board/plans/{id_or_code}/revisions List revisions for a plan
POST /v1/board/plans/{id_or_code}/revisions Create a new revision

SDK Examples

// Create a plan with initial content
const plan = await client.board.createPlan({
  title: 'Q3 Roadmap',
  body: '## Goals\n- Launch v2\n- Onboard 10 customers',
});

// Create a revision when updating
await client.board.createRevision(plan.id, {
  body: '## Goals (revised)\n- Launch v2.1\n- Onboard 20 customers',
  summary: 'Revised targets after board review',
});
// Rust SDK
let plan = client.board().create_plan(CreatePlanRequest {
    title: "Q3 Roadmap".into(),
    body: Some("## Goals\n- Launch v2\n- Onboard 10 customers".into()),
    ..Default::default()
}).await?;

client.board().create_revision(&plan.id.to_string(), CreateRevisionRequest {
    body: "## Goals (revised)\n- Launch v2.1\n- Onboard 20 customers".into(),
    summary: Some("Revised targets after board review".into()),
}).await?;

Products

Products represent logical product lines or applications that stories and plans belong to.

MethodPathDescription
GET /v1/board/products List all products for the org
POST /v1/board/products Create a product
GET /v1/board/products/{slug} Get a product by slug or UUID
PATCH /v1/board/products/{slug} Update a product

SDK Examples

// Create a product
const product = await client.board.createProduct({
  name: 'Dashboard',
  slug: 'dashboard',
  description: 'Internal analytics dashboard',
});

// List all products
const { data: products } = await client.board.listProducts();
// Rust SDK
let product = client.board().create_product(CreateProductRequest {
    name: "Dashboard".into(),
    slug: "dashboard".into(),
    description: Some("Internal analytics dashboard".into()),
}).await?;

let products = client.board().list_products().await?;

Comments

Comments can be attached to any target (story, sprint, plan) via a target_type and target_id.

MethodPathDescription
GET /v1/board/comments List comments (filter by target_type + target_id)
POST /v1/board/comments Create a comment
PUT /v1/board/comments/{id} Update a comment
DELETE /v1/board/comments/{id} Delete a comment

SDK Examples

// Add a comment to a story
const comment = await client.board.createComment({
  target_type: 'story',
  target_id: storyId,
  body: 'Ready for review',
});

// List comments for a story
const { data: comments } = await client.board.listComments({
  target_type: 'story',
  target_id: storyId,
});

// Update a comment
await client.board.updateComment(comment.id, {
  body: 'Approved and merged',
});
// Rust SDK
let comment = client.board().create_comment(CreateCommentRequest {
    target_type: "story".into(),
    target_id: story_id,
    body: "Ready for review".into(),
}).await?;

let comments = client.board().list_comments(ListCommentsQuery {
    target_type: Some("story".into()),
    target_id: Some(story_id),
    ..Default::default()
}).await?;

client.board().update_comment(comment.id, UpdateCommentRequest {
    body: "Approved and merged".into(),
}).await?;