The Octopus.do Public API lets you create and manage projects, sitemaps, workspaces, and folders from your own code — the same actions available in the app and to AI agents over MCP. This page mirrors the interactive reference; you can try any request live in the Swagger UI.
Base URL
https://openapi.octopus.do
All paths below are relative to this base — for example GET https://openapi.octopus.do/v1/my. Requests and responses are JSON.
Authentication
Every /v1 endpoint requires authentication. Two schemes are supported:
- API key — send an
X-API-Keyheader. Best for development and server-to-server clients. - OAuth 2.1 (Bearer) — send an
Authorization: Bearer <token>header. Used by ChatGPT and other MCP clients.
There are no separate public register/login REST endpoints — sign-up and sign-in for API consumers go through the OAuth 2.1 flow (/oauth/authorize handles registration and login).
Example request with an API key:
curl https://openapi.octopus.do/v1/my \
-H "X-API-Key: YOUR_API_KEY"
Account
GET/v1/my
Returns your profile and every workspace you can access (personal and teams). No parameters.
Projects
POST/v1/projects/create
Creates a project in the target workspace. Returns 201.
| Field | Required | Type | Description |
|---|---|---|---|
workspace_id | Yes | string | Body — destination workspace — a team workspace uuid, or the literal my for your personal space. Required; an empty or omitted value is rejected with an error. |
folder_id | No | string | Body — folder id within the team workspace |
GET/v1/projects/{uuid}
Returns a project's full state — the sitemap tree, pages, blocks, colors, tags, symbols, and sharing/ownership info.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
action_id | No | number | Query — return the project state at a specific action revision |
view | No | string | Query — outline (default): the page tree with titles, urls and ids; full: page content as well |
scope_id | No | string | Query — read one branch instead of the whole project: a tab, section or page id. The response carries the chain of ancestors so the branch keeps its context |
exclude | No | string | Query — CSV of content groups to drop: blocks, content, notes, styling, tags, estimates, overlays, meta |
format | No | string | Query — nested (default) or plain |
POST/v1/projects/{uuid}/duplicate
Duplicates a project into a new one.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
POST/v1/projects/{uuid}/archive
Archives a project.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
POST/v1/projects/{uuid}/unarchive
Restores an archived project.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
POST/v1/projects/{uuid}/move
Moves a project within a team workspace, or back to your personal space. To change the owner instead, use transfer.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
workspace_id | Yes | string | Body — destination workspace — a team workspace uuid, or the literal my for your personal space. Required; an empty value is rejected with an error. |
folder_id | No | string | Body — destination folder id; omit to place it at the team root |
POST/v1/projects/{uuid}/transfer
Transfers project ownership to another user by email.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
email | Yes | string | Body — recipient email; must be a registered, non-free-plan user |
Comments
Comments come in two shapes and the API keeps them apart. A comment is a flat note left on a page or on a content block. A thread is a canvas pin: it has an x/y position, it is anchored to a page or to a tab, it is either open or resolved, and its replies are comments. Only a thread has a resolved state — a page or block comment has none at all, and carries no field to set.
content is an editor document: the editor serializes a Plate/Slate document to a JSON string, and that is what you read back. Send plain text — it is wrapped on write into an editor document, one paragraph per line, which is what a person typing the same text would have produced. Stored verbatim it would render as nothing at all, which is why the API does this for you rather than trusting it through. A value that is already a serialized document is kept byte-for-byte, so nobody's formatting is rewritten, and text that merely starts with a bracket is treated as the text it is. On the way back, treat the value as opaque: three encodings coexist in stored data and parsing it means guessing between them.
author is an opaque user uuid — never a name, an email or an avatar — and it is null when the comment was left by an anonymous commenter. Two notes from the same person carry the same uuid, which is enough to tell reviewers apart.
A comment created through this API is authored by the owner of the API key that created it, with no marker of any kind: in the editor it is indistinguishable from one that person typed. It also notifies nobody — no mentions are sent.
Reads need a key with a read scope and writes need a write scope, the same as every other endpoint on this page.
GET/v1/projects/{uuid}/comments
Lists the page comments, block comments and thread replies in a project, as comments. Each entry carries id, kind (page | block | reply), target ({ "type": …, "id": … }), thread_id — set only when kind is reply, null otherwise — content, author, created_at and updated_at. Canvas threads are not in this list; read those from /threads.
This endpoint does not read the project itself, which has two consequences worth knowing before you build on it: a project you cannot see answers with an empty list rather than a 403, so "no access" and "no comments yet" look identical from outside; and a read-only share uuid is accepted here, where /threads takes the project uuid only.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
target_id | No | string | Query — only comments on this exact id: a page id, a block id, or a thread id, which returns that thread's replies |
kind | No | enum | Query — page | block | reply; repeat the parameter or comma-join the values to ask for several. comment is not one of them and is rejected with a 400 |
POST/v1/projects/{uuid}/comments
Adds a note on a page, on a content block, or as a reply to an existing canvas thread, and returns the created comment. To create the thread itself — a pin with a position — use /threads instead.
The target is checked against the project before anything is written. An id the project does not contain is a 404, and an id of the wrong kind — a block id sent as page, the easy mistake, since the two are indistinguishable by eye — is a 400 naming what the id really is. Neither is worth retrying: re-read the ids from GET /v1/projects/{uuid}.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
target | Yes | object | Body — what the comment hangs off: { "type": "page" | "block" | "thread", "id": "…" }, where the id is a page id, a block id, or the thread being replied to |
content | Yes | string | Body — the comment body; must not be empty. Plain text is fine and is the normal case — it is wrapped into an editor document, one paragraph per line; a serialized document is stored untouched |
idempotency_key | No | string | Body — send the same key on a retry and the comment is created once |
DELETE/v1/projects/{uuid}/comments/{comment_id}
Deletes one page comment, block comment or thread reply. Responds { "ok": true }. The comment must belong to the project in the path — one from another project is a 404 — and a comment that is not yours to delete answers 404 as well, so "already gone" and "not yours" are not distinguishable.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
comment_id | Yes | string | Path — comment id |
GET/v1/projects/{uuid}/threads
Lists the canvas threads — the pins on the project canvas — as threads. Open threads only, by default: pass resolved=true for the settled ones. Each entry carries id, anchor ({ "type": …, "id": … }), position ({ "x": 0, "y": 0 }), content, resolved, author, reply_count, created_at and updated_at, plus a replies array when include=replies was asked for.
An anchor.type of null means the page or tab the pin was placed on has been deleted and the pin outlived it — anchor.id now points at nothing. Orphaned pins are normal: deleting a page never deletes the pins on it.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
resolved | No | boolean | Query — false (the default) returns the open threads, true the resolved ones. Parsed strictly: any other value — yes, or an empty resolved= from an unset client template — is rejected with a 400 rather than falling back to the default |
include | No | string | Query — replies embeds each thread's replies in a replies array. It is the only accepted value; all is a 400 |
POST/v1/projects/{uuid}/threads
Creates a canvas thread — a pin anchored to a page or to a tab — and returns it. Replies are added with /comments and a target of type thread.
The anchor is checked against the project first, so a bad id is a 404 rather than a pin that renders nowhere, and an id of the wrong kind is a 400 naming what it really is.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
anchor | Yes | object | Body — where the pin sits: { "type": "page" | "tab", "id": "…" }. A concrete type is required here; null only ever comes back, on an orphaned pin |
content | Yes | string | Body — the thread body; must not be empty. Same handling as a comment: plain text becomes an editor document, a document is kept |
position | No | object | Body — the pin position, { "x": 0, "y": 0 }; defaults to { "x": 0, "y": 0 } |
idempotency_key | No | string | Body — send the same key on a retry and the thread is created once |
DELETE/v1/projects/{uuid}/threads/{thread_id}
Deletes a canvas thread. Its replies are left behind — they are comments in their own right, and deleting the thread does not delete them. Responds { "ok": true }.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
thread_id | Yes | string | Path — thread id |
POST/v1/projects/{uuid}/threads/{thread_id}/resolve
Resolves a canvas thread, or reopens one. Only threads have a resolved state — there is no equivalent for a page comment or a block comment. Responds { "ok": true }.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
thread_id | Yes | string | Path — thread id |
resolved | Yes | boolean | Body — true to resolve the thread, false to reopen it |
idempotency_key | No | string | Body — send the same key on a retry and the change is applied once |
Editing the sitemap
These project-scoped endpoints build and restructure a sitemap — pages (nodes), content blocks, tabs, sections, colors, symbols, tags, arrows, sticky notes, external links, and estimates. They mirror the tools available to AI agents over MCP.
Every write endpoint accepts an optional idempotency_key (string): a unique key that makes retries safe — a repeated request with the same key is applied only once. It is omitted from the tables below.
Batch
POST/v1/projects/{uuid}/batch
Apply several operations as one atomic change. Operations run in order and each sees the effect of the previous ones. Give a created entity a ref and reference it in later operations via *_ref fields (e.g. parent_ref) instead of an id.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
operations | Yes | array | Body — at least one operation (see below) |
dry_run | No | boolean | Body — validate and preview only; nothing is changed |
Each operation:
| Field | Required | Type | Description |
|---|---|---|---|
operation | Yes | string | Operation name, e.g. "nodes.create" |
ref | No | string | Local name for the created entity, referenced later via *_ref fields |
data | No | object | Operation payload — same fields as the matching standalone endpoint |
A successful response may also carry warnings — advisory notes such as a page whose url does not sit under its parent's path. Nothing was blocked and nothing needs retrying; they report what an editor would have noticed by eye.
Operation names follow group.action, with both halves in snake_case. The path of the matching standalone endpoint spells the same operation with hyphens (/tags/assign-node ↔ tags.assign_node); the two forms are not interchangeable, and an operation named in path form is rejected with Unknown operation.
| Group | Actions |
|---|---|
nodes | create, update, move, clone, collapse, delete, replace_url_prefix |
blocks | create, update, move, clone, delete, link_symbol, unlink_symbol |
tabs | create, update, move_up, move_down, clone, delete |
sections | create, update, move_up, move_down, clone, collapse, delete |
colors | create, update, delete |
symbols | create, update, delete |
tags | create, update, delete, assign_node, unassign_node |
arrows | create, update, delete |
sticky_notes | create, update, clone, delete |
external_links | create, update, clone, delete |
estimates | update_settings, add_line_item, update_line_item, delete_line_item, set_value |
settings | update |
Nodes (pages)
POST/v1/projects/{uuid}/nodes/create
Create a node (page).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
parent_id | Yes | string | Body — Parent id — a tab, section or node. A tab parent places the node in its first section |
title | No | string | Body — Page title |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
color_id | No | string | Body — Project color id; defaults to the project's default color |
url | No | string | Body — Page URL/slug shown on the node |
variant | No | enum | Body — default | frame | ghost | stack |
after_id | No | string | Body — place it directly after this sibling; decides the parent too, so parent_id is not needed |
before_id | No | string | Body — place it directly before this sibling |
index | No | number | Body — Position among the parent children; omit to append |
POST/v1/projects/{uuid}/nodes/update
Update node fields (title, color, url, variant, SEO notes).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes* | string | Body — Node id. Required unless ids is given |
ids | No | array | Body — several node ids instead of id, one operation for the lot. Only color_id, variant and notes apply in bulk — title and url would land the same value on every page. Duplicates are ignored and counted back |
title | No | string | Body — New title |
color_id | No | string | Body — Project color id |
url | No | string | null | Body — Page URL/slug; pass null to clear |
variant | No | enum | Body — default | frame | ghost | stack |
notes | No | object | Body — SEO/notes fields to set (merged with existing): note, keywords, page_intent, seo_title, seo_description, seo_h1, seo_slug, seo_url |
POST/v1/projects/{uuid}/nodes/replace-url-prefix
Rewrite the start of every matching page url in one operation — /hawaii-… to /hi-… across a whole branch, instead of one nodes/update per page. The match is literal and case-sensitive, so the affected set is exactly predictable from the payload; if nothing matches, the call fails rather than reporting a silent no-op.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
from | Yes | string | Body — url prefix to match at the start, e.g. /hawaii. Must not be empty |
to | Yes | string | Body — replacement prefix; pass an empty string to strip the prefix |
scope_id | No | string | Body — limit to a tab, section or page; omit to rewrite the whole project |
POST/v1/projects/{uuid}/nodes/move
Move a node (with its subtree) to another parent.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Node id to move |
parent_id | Yes | string | Body — New parent — a tab, section or node (not the node itself or its subtree) |
after_id | No | string | Body — place it directly after this sibling; decides the parent too, so parent_id is not needed |
before_id | No | string | Body — place it directly before this sibling |
index | No | number | Body — Position among the new parent children; omit to append |
POST/v1/projects/{uuid}/nodes/clone
Clone a node with its subtree and blocks.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/nodes/collapse
Collapse or expand a node subtree.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
collapsed | No | boolean | Body — true to collapse (default), false to expand |
POST/v1/projects/{uuid}/nodes/delete
Delete a node with its subtree and blocks.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Node id — deletes the node with its whole subtree and blocks |
Blocks
POST/v1/projects/{uuid}/blocks/create
Create a content block inside a node.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
node_id | Yes | string | Body — Node (page) id the block is created in |
title | No | string | Body — Block title |
content | No | string | Body — Block text content |
wireframes | No | array | Body — Wireframe names to render, e.g. ['header'], ['text', 'cta'] |
color_id | No | string | Body — Project color id; defaults to the project's default color |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
index | No | number | Body — Position within the node; omit to append |
POST/v1/projects/{uuid}/blocks/update
Update block fields (title, content, color, wireframes, flags).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Block id |
title | No | string | Body — New title |
content | No | string | Body — New text content |
color_id | No | string | Body — Project color id |
wireframes | No | array | Body — Wireframe names |
collapsed | No | boolean | Body — |
completed | No | boolean | Body — |
POST/v1/projects/{uuid}/blocks/move
Move a block to another node.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Block id to move |
node_id | Yes | string | Body — Destination node (page) id |
index | No | number | Body — Position within the destination node; omit to append |
POST/v1/projects/{uuid}/blocks/clone
Clone a block.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/blocks/delete
Delete a block.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Block id |
POST/v1/projects/{uuid}/blocks/link-symbol
Link a block to a symbol (it becomes an instance sharing the symbol content).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Monolithic block id to turn into a symbol instance |
symbol_id | Yes | string | Body — Symbol to link the block to |
POST/v1/projects/{uuid}/blocks/unlink-symbol
Detach a block from its symbol (it keeps a standalone copy of the content).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
Tabs
POST/v1/projects/{uuid}/tabs/create
Create a tab (a page of the sitemap canvas).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
title | No | string | Body — Tab title |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
index | No | number | Body — Position; omit to append to the end |
POST/v1/projects/{uuid}/tabs/update
Rename a tab.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Tab id |
title | Yes | string | Body — New tab title |
POST/v1/projects/{uuid}/tabs/move-up
Move a tab one position up in the tab list.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/tabs/move-down
Move a tab one position down in the tab list.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/tabs/clone
Clone a tab with all its content.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/tabs/delete
Delete a tab with all its content.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
Sections
POST/v1/projects/{uuid}/sections/create
Create a section inside a tab.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
tab_id | Yes | string | Body — Tab id the section is created in |
title | No | string | Body — Section title |
color_id | No | string | Body — Project color id; defaults to the project's default color |
text_size | No | enum | Body — Title text size — l | m | s |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
index | No | number | Body — Position; omit to append |
POST/v1/projects/{uuid}/sections/update
Update section fields (title, color, text size).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Section id |
title | No | string | Body — New title |
color_id | No | string | Body — Project color id |
text_size | No | enum | Body — l | m | s |
POST/v1/projects/{uuid}/sections/move-up
Move a section up within its tab.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/sections/move-down
Move a section down within its tab.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/sections/clone
Clone a section with its content.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/sections/collapse
Collapse or expand a section.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
collapsed | No | boolean | Body — true to collapse (default), false to expand |
POST/v1/projects/{uuid}/sections/delete
Delete a section with its nodes.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
Colors
POST/v1/projects/{uuid}/colors/create
Add a color to the project palette.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
hex_code | No | string | Body — Hex color |
title | No | string | Body — Color name shown in the legend |
show_in_legend | No | boolean | Body — Show this color in the map legend |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
POST/v1/projects/{uuid}/colors/update
Update a palette color (name, hex, legend, order).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Color id |
title | No | string | Body — New name |
hex_code | No | string | Body — New hex value |
show_in_legend | No | boolean | Body — |
order | No | number | Body — Position in the palette |
POST/v1/projects/{uuid}/colors/delete
Delete a palette color, repainting everything with a replacement color.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Color id to delete |
replace_with_color_id | Yes | string | Body — Existing color that everything painted with the deleted color switches to |
Symbols
POST/v1/projects/{uuid}/symbols/create
Create a reusable symbol (optionally extracted from an existing block).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
title | No | string | Body — Symbol title |
content | No | string | Body — Symbol text content |
wireframes | No | array | Body — Wireframe names |
color_id | No | string | Body — Project color id; defaults to the project's default color |
from_block_id | No | string | Body — Extract the symbol from this monolithic block: the block content becomes the symbol and the block turns into its first instance |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
POST/v1/projects/{uuid}/symbols/update
Update a symbol — every linked block reflects the change.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Symbol id |
title | No | string | Body — New title |
content | No | string | Body — New text content |
color_id | No | string | Body — Project color id |
wireframes | No | array | Body — Wireframe names |
POST/v1/projects/{uuid}/symbols/delete
Delete a symbol; linked blocks are detached with a copy of the content.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
Tags
POST/v1/projects/{uuid}/tags/create
Create a tag.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
title | No | string | Body — Tag title |
color_id | No | string | Body — Project color id; defaults to the project's default color |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
POST/v1/projects/{uuid}/tags/update
Update a tag (title, color, order).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Tag id |
title | No | string | Body — New title |
color_id | No | string | Body — Project color id |
order | No | number | Body — Position in the tag list |
POST/v1/projects/{uuid}/tags/delete
Delete a tag (nodes keep their other tags).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/tags/assign-node
Assign a tag to a node.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Tag id |
node_id | Yes | string | Body — Node id |
POST/v1/projects/{uuid}/tags/unassign-node
Remove a tag from a node.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Tag id |
node_id | Yes | string | Body — Node id |
Arrows
POST/v1/projects/{uuid}/arrows/create
Draw an arrow between two nodes.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
from_id | Yes | string | Body — Source node id |
to_id | Yes | string | Body — Target node id (must differ from from_id) |
type | No | enum | Body — grid | smooth | straight |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
POST/v1/projects/{uuid}/arrows/update
Change an arrow line style.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Arrow id |
type | Yes | enum | Body — Line style — grid | smooth | straight |
POST/v1/projects/{uuid}/arrows/delete
Delete an arrow.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
Sticky notes
POST/v1/projects/{uuid}/sticky-notes/create
Place a sticky note on a tab canvas.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
tab_id | Yes | string | Body — Tab id the note is placed on |
content | No | string | Body — Note text |
color | No | enum | Body — Note color — the editor supports exactly three: yellow (#fefa6c), cyan (#c5f1ff), pink (#ffd2fb). Accepts a name or its hex value; default yellow — yellow | cyan | pink | #fefa6c | #c5f1ff | #ffd2fb |
x | No | number | Body — Canvas X position (default 40) |
y | No | number | Body — Canvas Y position (default 40) |
width | No | number | Body — Width in px (default 128, as in the editor) |
height | No | number | Body — Height in px (default 140, as in the editor) |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
index | No | number | Body — |
POST/v1/projects/{uuid}/sticky-notes/update
Update a sticky note (text, color, position, size).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Sticky note id |
content | No | string | Body — New text |
color | No | enum | Body — New color — yellow (#fefa6c), cyan (#c5f1ff) or pink (#ffd2fb); name or hex — yellow | cyan | pink | #fefa6c | #c5f1ff | #ffd2fb |
x | No | number | Body — |
y | No | number | Body — |
width | No | number | Body — |
height | No | number | Body — |
POST/v1/projects/{uuid}/sticky-notes/clone
Clone a sticky note.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/sticky-notes/delete
Delete a sticky note.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
External links
POST/v1/projects/{uuid}/external-links/create
Add an external link card to a tab canvas.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
tab_id | Yes | string | Body — Tab id the link card is placed on |
url | Yes | string | Body — Link URL (http/https) |
title | No | string | Body — Card title |
x | No | number | Body — Canvas X position (default 40) |
y | No | number | Body — Canvas Y position (default 40) |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
index | No | number | Body — |
POST/v1/projects/{uuid}/external-links/update
Update an external link (url, title, position).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — External link id |
url | No | string | Body — New URL (http/https) |
title | No | string | Body — New card title |
x | No | number | Body — |
y | No | number | Body — |
POST/v1/projects/{uuid}/external-links/clone
Clone an external link.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/external-links/delete
Delete an external link.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
Estimates
POST/v1/projects/{uuid}/estimates/update-settings
Update estimate settings (currency, units, tax, visibility).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
currency | No | string | Body — ISO 4217 code |
units | No | enum | Body — hours / days / weeks — h | d | w |
tax_enabled | No | boolean | Body — Apply tax on top of the total |
tax_value | No | number | Body — Tax percent |
hidden | No | boolean | Body — Hide estimates on the map |
POST/v1/projects/{uuid}/estimates/add-line-item
Add an estimate line item (e.g. Design at 50/unit).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
title | No | string | Body — Line item name |
rate | No | number | Body — Rate per unit (money) |
id | No | string | Body — Client-supplied id; omit to let the server generate one |
POST/v1/projects/{uuid}/estimates/update-line-item
Update an estimate line item (name, rate).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Line item id |
title | No | string | Body — New name |
rate | No | number | Body — New rate per unit |
POST/v1/projects/{uuid}/estimates/delete-line-item
Delete an estimate line item with its per-node values.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
id | Yes | string | Body — Entity id |
POST/v1/projects/{uuid}/estimates/set-value
Set a node's estimate value for a line item (creates it on first use).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
node_id | Yes | string | Body — Node (page) id the estimate belongs to |
line_item_id | Yes | string | Body — Line item id the value is for |
value | Yes | number | Body — Amount of units (e.g. hours) |
Settings
POST/v1/projects/{uuid}/settings/update
Update project settings (title, theme, layout, default color).
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — project uuid |
title | No | string | Body — Project title |
theme | No | enum | Body — blueprint | bold | dark | light |
tree | No | enum | Body — Tree layout — map | matrix |
frame | No | enum | Body — Node frame style — mobile | neutral | web |
mobile | No | boolean | Body — Mobile mode |
image_mode | No | boolean | Body — Show images on nodes |
legend_position | No | enum | Body — bottom | none | top |
default_color_id | No | string | Body — Default color id for new entities |
avatar | No | string | null | Body — Project avatar url; pass null to clear |
Workspaces
GET/v1/workspaces/{uuid}
Returns one workspace: info, members, projects, and folders.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — workspace uuid, or the literal my for your personal workspace. An empty value is rejected with an error. |
Folders
POST/v1/workspaces/{uuid}/folders
Creates a folder in a team workspace.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — workspace uuid |
title | Yes | string | Body — folder title |
PATCH/v1/workspaces/{uuid}/folders/{folder_id}
Renames a folder.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — workspace uuid |
folder_id | Yes | string | Path — folder id |
title | Yes | string | Body — new folder title |
DELETE/v1/workspaces/{uuid}/folders/{folder_id}
Deletes a folder.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Path — workspace uuid |
folder_id | Yes | string | Path — folder id |
OAuth 2.1
These endpoints implement the OAuth 2.1 / MCP authorization flow. They are called by MCP clients during sign-in — you rarely call them from your own code — and they require no prior authentication.
POST/oauth/token
Exchanges an authorization code for tokens, or rotates a refresh token. Body is application/x-www-form-urlencoded. Errors use the RFC 6749 shape ({ "error": "invalid_grant" }).
| Field | Required | Type | Description |
|---|---|---|---|
grant_type | Yes | enum | authorization_code | refresh_token |
client_id | Yes | string | OAuth client id |
code | No | string | authorization_code grant |
redirect_uri | No | string | authorization_code grant |
code_verifier | No | string | authorization_code grant (PKCE) |
refresh_token | No | string | refresh_token grant |
POST/oauth/register
Dynamic Client Registration (RFC 7591). Registers a public OAuth client; no secret is issued (token_endpoint_auth_method: none).
| Field | Required | Type | Description |
|---|---|---|---|
redirect_uris | Yes | string[] | Allowed redirect URIs |
client_name | No | string | Human-readable client name |
POST/oauth/revoke
Revokes an access or refresh token (RFC 7009). Always returns 200, even for unknown tokens.
| Field | Required | Type | Description |
|---|---|---|---|
token | Yes | string | The token to revoke |
GET/.well-known/oauth-authorization-server
Authorization-server metadata (RFC 8414): the OAuth 2.1 endpoints, supported scopes, grant types, and PKCE methods. Fetched automatically by MCP clients. No parameters.
GET/.well-known/oauth-protected-resource
Protected-resource metadata (MCP authorization spec): declares this API as a protected resource and points to its authorization server. No parameters.
Learn more
- Interactive API reference (Swagger UI): https://openapi.octopus.do/docs
- Use Octopus from AI agents (MCP): Octopus MCP
- Octopus.do: https://octopus.do/