---
title: "Create or update a text node"
method: POST
path: "/api/boards/{boardId}/texts"
tags: ["Items"]
---

# Create or update a text node

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

## Request

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

Mirrors the MCP `add_text` tool. Creates a NEW text node with a fresh UUID, OR updates an existing node if you pass its `id` (preferred over creating duplicates). Content supports cnvs markup (Markdown-ish, including `[]` / `[ ]` / `[x]` task-list checkboxes that render as clickable circles and toggle in source on click) and Mermaid diagrams — when using Mermaid, the ENTIRE content must be a single ```mermaid fenced block (one diagram per node). Set `postit: true` for a yellow sticky-note style.

## Request body

- AddTextRequest
  - `id` string: Optional stable id. Pass an existing id to UPDATE that node in place; omit to CREATE a new one with a fresh UUID.
  - `x` number, required: World x (+x right).
  - `y` number, required: World y (+y DOWN, standard SVG).
  - `content` string, required: Raw content (up to 100 000 chars). Supports cnvs markup (Markdown-ish) and Mermaid (one diagram per node — entire content must be a single ```mermaid fenced block).
  - `color` 'auto' | 'black' | 'red' | 'blue' | 'green' | 'orange' | 'yellow' | 'pink' | 'purple' | 'maroon' | 'brown' | 'gray' | 'lightgray' | 'teal' | 'sage' | 'sky' | 'lavender': Ink color NAME — same mental model as clicking the ink picker. Case-insensitive. `auto` / `black` / omitted → theme-aware. `red` / `blue` / `green` and the extended palette (`orange`, `yellow`, `pink`, `purple`, `maroon`, `brown`, `gray`, `lightgray`, `teal`, `sage`, `sky`, `lavender`) → emphasis colors. Custom hex codes silently clamp to `auto` so AI writes never end up invisible on dark mode.
  - `width` number, nullable: Explicit width in px (160–4096), or null for auto-fit.
  - `postit` boolean: Renders as a yellow sticky note when true.
  - `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`

Text created or updated.

- AddTextResponse
  - `id` string, required
  - `x` number, required
  - `y` number, required
  - `content` string, required
  - `postit` boolean
  - `author` string

## 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)
