Skip to main content

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 returns documents the authenticated user owns or that have been shared with them — including shares granted through a team they belong to. Deleting a document is restricted to its owner and is a recoverable soft-delete.

Writing markdown content requires edit access (owner, or a participant with the admin or member role, including team-shared editors). Viewers and comment-only participants receive 403 Forbidden. Callers who cannot see the document at all get the same "Document not found" error as other read endpoints.

Browsing the tree​

The tree endpoint walks the hierarchy breadth-first:

  • Call it without a parentId for 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 — POST a title, with an optional parent (for nesting) and optional initial content.
  • Update metadata — PATCH to change the title, icon, or cover.
  • 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.

tip

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​