---
title: "Create or update a kanban task"
method: POST
path: "/api/boards/{boardId}/tasks"
tags: ["Kanban"]
---

# Create or update a kanban task

`POST /api/boards/{boardId}/tasks`

## Request

- Base URL: `https://cnvs.app`
- URL: `https://cnvs.app/api/boards/{boardId}/tasks`
- Auth: none declared

Mirrors the MCP `create_task` / `update_task` tools. Only valid on a `todo`-mode board. Creates a NEW task with a fresh UUID, OR updates an existing task in place if you pass its `id`. Max 1000 tasks per board, 20 000 chars per task content. In the snapshot a task's `content` is an opaque JSON string (e.g. `{"description":...}`) — treat it as a blob. It may also carry an optional `boards` array of attached cnvs board ids (`{"boards":["<id>",...]}`), set when a user drags boards from their Recent rail onto the task.

Over MCP there are extra task tools without a dedicated REST path: `create_tasks` (bulk-create an array in one call), `query_tasks` (server-side filter by assignee / priority / done / overdue / due-window), and `export_tasks` (the same output as `GET tasks.csv` / `tasks.md`). `due_date` must be an ISO 8601 date (`YYYY-MM-DD` or full date-time); non-ISO values are rejected `400 { field: "due_date" }`.

## Request body

- AddTaskRequest
  - `id` string: Pass an existing id to UPDATE that task in place; omit to CREATE a new one.
  - `column_id` string, required: Column the card belongs to.
  - `name` string, required: Card title.
  - `description` string: Optional free-text body. Stored inside the task's opaque `content` JSON blob (≤ 20 000 chars).
  - `due_date` string: Optional ISO 8601 due date.
  - `priority` 'H' | 'M' | 'L': Optional High / Medium / Low priority.
  - `assignee` string: Optional assignee label.
  - `done` boolean: Mark the task completed (checked off). Defaults to false on create; omit on update to leave unchanged.
  - `sort` number: Optional order within the column.
  - `author` string: Author tag, charset `[A-Za-z0-9:_\-.]`, max 80 chars. Defaults to `ai:rest` for REST mutations. Use `ai:<your-label>` (e.g. `ai:claude`, `ai:mybot`) so humans can tell AI edits apart.

## Response `200`

Task created or updated.

- Task: A kanban task (card) on a `todo`-mode board.
  - `id` string, required
  - `column_id` string, required: Column the card currently lives in.
  - `name` string, required: Card title.
  - `content` string, nullable: Opaque JSON string blob, e.g. `{"description":...}`. Treat as a blob — do not parse application meaning out of it. Max 20 000 chars.
  - `due_date` string, nullable: ISO 8601 due date, or null.
  - `priority` 'H' | 'M' | 'L' | 'null', nullable: High / Medium / Low, or null.
  - `assignee` string, nullable
  - `done` boolean: Whether the task is completed (checked off). Defaults to false.
  - `sort` number: Order within the column.
  - `author` string, nullable
  - `last_updated` string: UTC timestamp.

## Other responses

- `400`: Invalid input (missing or malformed board id).
- `401`: Board is access-locked and the request did not carry a valid key. `lockMode` tells the client whether to prompt for a code or just disable write UI.
- `404`: Board does not exist or was deleted within the 30-day tombstone window.
- `413`: Per-board quota exceeded (too many texts, images, strokes, or total image bytes). Response body names the specific limit that was hit.
- `429`: Rate limit exceeded. Standard REST/MCP: 60 requests/10s/board; valid X-Import-Token infrastructure tier: 600/10s/board; browser WebSocket always 60/10s/board. REST/MCP enforcement is soft per-isolate; WebSocket enforcement is strong per Durable Object.

---

[API](https://skmtc.dev/cnvs/apis/cnvs-app-http-api.md) · [All operations](https://skmtc.dev/cnvs/apis/cnvs-app-http-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cnvs/apis/cnvs-app-http-api/revisions/c8f2c3b7ff90?raw)
