REST API
CompassDocs ships a small, stable REST API at /api/v1 for scripting and
integrations: CI jobs that update runbooks, exporters, dashboards, or anything
else that shouldn’t need a browser session.
Authentication
Section titled “Authentication”Every request needs a personal access token in the Authorization header:
curl -H "Authorization: Bearer cdk_…" https://docs.example.com/api/v1/meCreate tokens under your name → Manage account → API tokens. Each token has scopes chosen at creation:
| Scope | Grants |
|---|---|
read |
All GET endpoints — documents, spaces, search. |
write |
Creating, editing, and trashing documents. |
A token can never do more than the person it belongs to: role, space access, and the approval workflow all still apply. Uncheck Allow writes when creating a token to mint a read-only one — enough for search and exports, and the safer default for anything that only consumes content. (The Claude connector needs a read + write token.)
Requests are rate-limited to 120/minute per user; over the limit you get
429. Tokens are shown once at creation, stored only as a hash, and revocable
any time from the same screen.
Endpoints
Section titled “Endpoints”GET /api/v1/me
Section titled “GET /api/v1/me”Token introspection — the user it acts as, their role, and the token’s scopes.
GET /api/v1/spaces
Section titled “GET /api/v1/spaces”Spaces visible to the token’s user, with slugs (used as the space parameter
elsewhere), visibility, and document counts.
GET /api/v1/documents
Section titled “GET /api/v1/documents”List documents, newest first. Query parameters:
| Parameter | Meaning |
|---|---|
space |
A space slug (e.g. engineering). |
status |
published or draft — drafts are visible to editors and up. |
limit / offset |
Paging; limit caps at 100 (default 25). |
Returns {items, total, limit, offset}. List items omit content; fetch a
single document for the full body.
From 1.18.0 this list, GET /api/v1/search and the document counts of GET /api/v1/spaces leave out
handbook-only documents in spaces
the token’s user can’t write in, as the app’s listings do. GET /api/v1/documents/:id still returns one to anyone who can read its space:
it hides documents from listings, it doesn’t restrict them.
POST /api/v1/documents
Section titled “POST /api/v1/documents”Create a document (needs write + the editor role + edit rights in the
space):
curl -X POST https://docs.example.com/api/v1/documents \ -H "Authorization: Bearer cdk_…" -H "Content-Type: application/json" \ -d '{"space":"engineering","title":"Deploy runbook","content":"…", "type":"sop","tags":["deploy"],"status":"published"}'type is one of sop | technical | policy | knowledge (default
knowledge). In a strict-approval workspace, an editor asking for
published gets a draft back with a note — publishing still goes through
review, same as the app.
GET /api/v1/documents/:id
Section titled “GET /api/v1/documents/:id”One document, content included. From 1.11.0 the document also carries
ack_required (whether readers must confirm it), ack_edit_default (ask,
material or reset: what the document does when its text changes, see
the edit default)
and ack: { confirmations, eligible, version }, the standing an integration
needs before it edits a policy: how many people have confirmed the version
everyone was last asked to confirm, how many are expected to, and that
version as Version history numbers it ("v12", or null before the first
version). The counts are facts whether or not the requirement is on.
PATCH /api/v1/documents/:id
Section titled “PATCH /api/v1/documents/:id”Partial update — send any of title, content, summary, tags, type,
status, plus an optional note (used as the version note). If the change
touches a published document and the token’s user can’t publish, the change is
queued as a change request and you get 202 {pending: true, change_request_id} — nothing goes live until an approver signs off.
Editing a policy. A change to the title or content of a published
document that requires read confirmation, or a status: "published" that
puts such a draft live when its text differs from the version people
confirmed, must say what readers should see: send ack_policy ("keep" for
an editorial fix, which leaves every confirmation standing; "reset" for a
material change, which asks everyone to re-confirm and tells them) with
ack_reason (a reset needs a reason of at least 10 characters; a keep
follows Program settings’ Require a reason for editorial fixes too;
longer reasons are cut at 500; recorded on the compliance record and, for a
reset, shown to readers; it is also the version note when note is
absent). Without ack_policy the call is refused with 428 Precondition
Required and nothing is written:
{ "error": "This document requires read confirmation. Pass ack_policy \"keep\" (editorial fix) or \"reset\" (material change), with ack_reason.", "decision_required": true, "confirmations": 42, "eligible": 50, "baseline": "v12", "change": { "pct": 1.1, "wordsChanged": 14, "blocksChanged": 1, "headingsChanged": 0, "numbersChanged": 0 }, "suggested": "keep"}confirmations and eligible are the standing, baseline the version
people confirmed, change the measured difference between that version and
what you sent (the same measure the editor’s question shows), and
suggested what that measure calls it. Show them to a person and call again
with the answer. A policy without a usable ack_reason (a reset with fewer
than 10 characters, or a keep with none while the setting is on) answers
400 ack_reason is required when the text of a confirmed policy changes.; any other value of ack_policy answers 400 ack_policy must be "keep" or "reset"., and the field is validated whenever it is sent, so a
bad value is refused even on a change that is not substantive. A PATCH that
only touches summary, tags, type or moves a published document back to
draft is never refused for want of a decision, and neither is an edit to a
draft that stays a draft (the decision is taken when it is published), nor
any edit to a document that does not require read confirmation. The response
carries the document with the fields GET returns and ack_outcome: { changed, substantive, reset, confirmations_reset, policy, source }, so a
script can log what its edit did. When the token’s user cannot publish, the
change is queued as before; ack_policy and ack_reason travel with the
change request as the submitter’s recommendation and the approver decides
(see the review queue).
Tokens never confirm. A token may edit a policy and must decide keep or
reset when it does; it can never record a read confirmation. POST /api/documents/{id}/ack and POST /api/documents/{id}/ack/reconfirm accept
the signed-in session only and answer 401 to any bearer, however valid, and
the connector has no tool that confirms. That is deliberate: a confirmation
is a person’s attestation, not an integration’s.
DELETE /api/v1/documents/:id
Section titled “DELETE /api/v1/documents/:id”Moves the document to the Trash (restorable in the app; permanent deletion follows the workspace retention setting).
GET /api/v1/search?q=
Section titled “GET /api/v1/search?q=”The same hybrid search as the app — full-text always, fused with semantic
retrieval when an embeddings provider is configured — including the
type: tag: space: author: status: operators:
curl -H "Authorization: Bearer cdk_…" \ "https://docs.example.com/api/v1/search?q=failover+space:engineering"Snippets come back as plain text.
Errors
Section titled “Errors”Errors are JSON with a human-readable message: 401 (missing/invalid token),
403 (missing scope, role, or edit rights), 404 (not found — including
documents outside the user’s space scope), 429 (rate limit), 400
(malformed input), 428 (a change to the text of a document that requires
read confirmation was sent without ack_policy; the body says what to
send).
The helpdesk API
Section titled “The helpdesk API”The helpdesk (enterprise) has its own REST API
from 1.19.4, under /api/helpdesk/v1, with its own tokens that act as a
desk role. See API tokens and webhooks.
Beyond REST
Section titled “Beyond REST”For AI-driven use, the Claude connector exposes the full editing surface over MCP — the REST API is the better fit for scripts and conventional integrations.
