apply_changes
ChatGPTApplies several editing operations to a project as ONE atomic change — the preferred way to build or restructure a sitemap. To restructure existing pages use nodes.move — never delete and recreate a page to relocate it (its content would be lost). Operations run in order and each sees the effect of the previous ones. Pick operation first: the schema then shows the data fields that operation takes, and each one names its parent in its own words — read the field list of the operation you picked. An operation that creates something can also take a ref: a local name later operations point at via the matching *_ref field instead of an id. Leave ref out on everything else, and whenever nothing later refers to what was created. Set dry_run: true to validate and preview without changing anything. Up to 100 operations per call, which is the API's own cap. Put as much of the job in ONE call as fits rather than splitting it up: a batch costs the same one write whether it carries 3 operations or 100, so splitting buys nothing and costs a round trip. A one-operation batch is right only when one change is genuinely all there is to make — if you are about to delete several pages, retitle several nodes, or clear starter pages, that is ONE call with several operations, not one call each. Only split what genuinely exceeds the cap, into sequential batches. ORDER MATTERS, and one case bites hard: emptying a container deletes it. Deleting the last page of a section removes the section, so any later operation naming that section — as parent_id, or as its own id — fails with "Not found" and takes the whole atomic batch with it, even though the id was valid when the batch was written. Verified against the live API. Deleting a page that still has siblings is safe anywhere in the batch. The rule that always works: create first, delete last. POSITION pages by naming a neighbour, not by counting: nodes.create and nodes.move take after_id/before_id (after_ref/before_ref for a page created earlier in this batch), which decide the parent too. An absolute index goes stale inside a batch — every earlier operation that inserts or removes a sibling shifts it — so prefer an anchor, and chain after_ref down a list of new pages to keep them in the order you wrote them. Never create a page and then move it into place: that is a second operation for something the create already does. Required data fields: every operation except the *.create ones and settings.update needs id (or id_ref) naming what it acts on. On top of that — sections.create {tab_id|tab_ref}; nodes.create and nodes.move {parent_id|parent_ref, or an after_id/before_id/after_ref/before_ref anchor instead}; blocks.create and blocks.move {node_id|node_ref}; sections.move_up and sections.move_down take only id and shift by ONE place, so moving a section N places is N of them in the same batch. Everything else takes only the fields being changed, e.g. blocks.create {node_ref, title, content, wireframes: ["header"]}. Content fields (block/symbol content, node notes.note) accept markdown or plain text and are read back as markdown. A successful result may include warnings[] — advisory notes about a change that WAS applied. They are not errors: nothing was rejected, nothing was half-applied, and repeating the call would duplicate the change. Pass the note to the user, or fix it with a follow-up edit, instead of retrying. One note exists today — URL_OUTSIDE_PARENT_PATH: a page whose url does not sit under its parent page's path, which is allowed and often deliberate (standalone SEO landing pages), so raise it rather than silently "correcting" a url the user chose. dry_run reports them too, so a preview shows what a commit would flag. The operations listed in the schema are the whole editing surface. If a request needs something none of them covers, say that it cannot be done here — never substitute a different operation for it, and never report it as done. Paid features follow the PROJECT OWNER's plan, which this server cannot report — and ONE gated operation fails th…
create_block
ChatGPTCreates a content block (low-fi wireframe) inside a node (page). Blocks work on every plan; the wireframes on them do not — the wireframes field below lists every valid key and names the subset a free-plan-owned project may use.
create_node
ChatGPTCreates a node (page) in the sitemap. The parent can be a tab, section or another node (ids come from get_project). The page can be POSITIONED as it is created rather than with a follow-up move_node — see after_id, before_id and index; with none of them it is appended. For several changes at once prefer apply_changes. A successful result may include warnings[] — notes about a change that WAS applied. They are not errors: nothing was rejected, and repeating the call would duplicate the change, so pass the note on or fix it with a follow-up edit instead of retrying. One code today, URL_OUTSIDE_PARENT_PATH: a page url outside its parent page's path — allowed and often deliberate (standalone SEO landings), so raise it rather than silently "correcting" it.
create_project
ChatGPTCreates a new octopus.do project — personal by default, or inside a team workspace. The new project's uuid comes back as project_id (and as uuid), and outline carries the starting tree it was created with — tabs, sections and starter pages, with their ids. That is everything a first edit needs: do NOT call get_project after this, and build the whole sitemap in ONE apply_changes call using those ids. A fresh project comes with starter pages; delete the ones you do not want with nodes.delete operations at the END of that same batch, never one call each — see apply_changes on why deleting them first can fail the batch. May fail with 403 when the plan's project limit is reached; the message covers both that and a workspace the user cannot access.
delete_block
ChatGPTDeletes a block from its node.
delete_node
ChatGPTDeletes a node WITH its whole subtree and all blocks inside. To relocate a page use move_node instead — deleting and recreating loses its content.
get_me
ChatGPTReturns the current octopus.do user's display name.
get_project
ChatGPTReturns one project by uuid as a tree: tabs → sections → pages (each page recurses via children); entity ids for edits sit directly on the tree nodes. DEFAULT is view: "outline" — that tree stripped to titles/urls/nesting, an order of magnitude cheaper in tokens and enough to answer "what pages are in this project" or to locate the page to edit. It carries page ids, so page-level edits need nothing more. Pass view: "full" only when the answer actually needs page content — blocks and their wireframes, notes, colors/tags, estimates, symbols/arrows/stickyNotes — and prefer narrowing it: scope_id to read one branch in full, exclude to drop content groups. A full read of a large project is big enough that some clients truncate it. To act on what you find: apply_changes for multi-step edits, create_node / update_node / create_block for single edits, move_node to relocate a page — never delete and recreate a page to move it (its blocks would be lost). Existing blocks also show valid wireframe keys (blocks[].wireframes). Page notes read back in camelCase (seoTitle) though written snake_case (seo_title) — same field, not missing SEO. meta.ownerPlan is the project OWNER's plan TIER — read it before any write: "free" (or null, enforced as free) allows only the free wireframe subset, node variant "default" and the plain note, and rules out tabs.create, symbols, colors, tags and the paid settings fields — apply_changes lists them; "pro", "team", "agency" have all of it. Apart from ownerPlan, meta carries only the project id and created/updated dates — no member data.
get_workspace
ChatGPTReturns one workspace by uuid: info, folders and projects. Use the literal uuid "my" for the personal workspace. Project uuids listed here feed get_project; create_project adds a project to this workspace.
list_projects
ChatGPTLists the projects the user can access, across every workspace, most recently updated first; each item names its workspace. Summaries only — get_project takes a uuid from here. At most 50 per call on an account that may hold hundreds: total is how many matched, has_more whether any were left out. To find ONE project use q — it searches the whole account, not this page. Page with offset only when the whole list is needed.
list_workspaces
ChatGPTLists the user's workspaces (personal + teams) with their folders and the 10 most recently updated projects in each — project_count gives the real total, list_projects searches and pages the rest. The personal workspace has the uuid "my".
manage_project
ChatGPTProject lifecycle actions: duplicate (copy), archive / unarchive, move (into a folder of a team workspace, or back to personal when workspace_id is omitted), transfer (give ownership to another user by email — the recipient must be a registered, non-free-plan user).
move_block
ChatGPTMoves a block to another node (page).
move_node
ChatGPTMoves a node with its whole subtree to another parent (tab, section or node), and/or REORDERS it among its siblings — reordering inside one section is this tool with an after_id/before_id anchor and no parent_id; with no anchor and no index it goes to the end of the new parent. A page is NOT pinned to where it was created: the new parent may be a different section, or a section in a different tab, and the page's children and blocks travel with it. ALWAYS use this (or apply_changes nodes.move) to restructure or nest existing pages — never delete and recreate a page to relocate it: that destroys its blocks and content. A successful result may include warnings[] — notes about a change that WAS applied. They are not errors: nothing was rejected, and repeating the call would duplicate the change, so pass the note on or fix it with a follow-up edit instead of retrying. One code today, URL_OUTSIDE_PARENT_PATH: a page url outside its parent page's path — allowed and often deliberate (standalone SEO landings), so raise it rather than silently "correcting" it.
update_block
ChatGPTUpdates block fields: title, text content, color, wireframes, collapsed/completed flags. The wireframes field below names the free-plan subset and where the full key list is.
update_node
ChatGPTUpdates node fields: title, color, url, variant, SEO notes (notes: {note, keywords, page_intent, seo_title, seo_description, seo_h1, seo_slug, seo_url} — all strings, merged with the existing notes). Every field is optional; only the ones passed change. A successful result may include warnings[] — advisory notes about a change that WAS applied. They are not errors: nothing was rejected, nothing was half-applied, and repeating the call would duplicate the change. Pass the note to the user, or fix it with a follow-up edit, instead of retrying. One note exists today — URL_OUTSIDE_PARENT_PATH: a page whose url does not sit under its parent page's path, which is allowed and often deliberate (standalone SEO landing pages), so raise it rather than silently "correcting" a url the user chose.
update_project_settings
ChatGPTUpdates project-level settings: title, theme, tree layout, page frame style, etc. PLAN GATE: image_mode and frame are Pro+ and fail with PLAN_REQUIRED when the PROJECT OWNER is on the free plan; title, theme, tree, legend and the rest work on every plan.
apply_changes
Claudecreate_block
Claudecreate_node
Claudecreate_project
Claudedelete_block
Claudedelete_node
Claudeget_me
Claudeget_project
Claudeget_workspace
Claudelist_projects
Claudelist_workspaces
Claudemanage_project
Claudemove_block
Claudemove_node
Claudeupdate_block
Claudeupdate_node
Claudeupdate_project_settings
Claude