How Docs Work
This page explains the document model and the mechanics behind every Docs operation: how documents nest into a tree, how access is scoped, how to browse the hierarchy lazily, how markdown content is read and written asynchronously, and how full-text search works. For a quick orientation and copy-paste examples, start with the Docs introduction.
The document model
A document has:
- Title — its name.
- Body — the rich-text content, read and written as markdown.
- Parent — an optional reference to another document, which is what builds the tree.
- Icon and Cover — optional emoji/icon and cover image.
Documents nest through their parent, forming a hierarchy:
Project Notes
├── Kickoff
│ └── Action Items (parent = Kickoff)
└── Retrospective (parent = Project Notes)
Documents without a parent sit at the root.
Access model
Access follows ownership and sharing. With a Personal Access Token, the API only returns documents the authenticated user owns or that have been shared with them as a participant. Deleting a document is restricted to its owner and is a recoverable soft-delete.
Browsing the tree
The tree endpoint walks the hierarchy breadth-first:
- Call it without a
parentIdfor root-level documents, or pass a document id to fetch that subtree. - Control how deep it descends with
depth(1–10, default 3).
Each node carries a hasChildren flag, which makes lazy-loading explorers easy — only fetch a deeper level when a user expands a node. The tree is capped at 500 documents per response; when it truncates, the response includes nextParentIds so you can continue fetching the remaining branches.
Reading and writing content
Content is always markdown. Read it from the document's …/md endpoint, which returns { "content": "…" } (an empty string when the document has no body).
To write content, POST to the same path with an operation and content:
replace— overwrite the entire body.append— add to the end.prepend— add to the beginning.
Content updates are asynchronous: the API queues the change and returns HTTP 202 Accepted. The new content appears a moment later. Creating a document with initial content follows the same async path — the page is created immediately and its body is filled in shortly after.
Managing documents
- Create —
POSTatitle, with an optionalparent(for nesting) and optional initialcontent. - Update metadata —
PATCHto change thetitle,icon, orcover. - Delete — soft-deletes the document (owner only; recoverable).
Searching
The search endpoint runs full-text search across every document you can access. Pass q for the query and optionally control sortBy (createdAt / updatedAt, default updatedAt), sortOrder (asc / desc, default desc), and limit (1–50, default 20).
Results come back with highlighted matches in the title and body, plus each hit's ancestor chain (parents), so you can show where a result lives in the tree.
For search that spans documents and other entity types (channels, todos, drive files, and more) in one call, use the global Search API instead.
Authentication & scope
Docs endpoints require a Personal Access Token (cp_pat_) with the access_docs scope. A token missing the scope gets a 403. See Authentication.
Reference
- Docs introduction — orientation, Quick Start, and parity.
- Docs in the API Reference — tree, search, get/create/update/delete, and markdown content endpoints with full schemas.
- Error Handling — note that "not found" cases surface as a
400with aNOT_FOUNDcode. - Copera CLI and MCP server.