Skip to main content
Everything Scribe can do is available through its REST API — the web app is just another client. Documents, folders, content, sharing, comment threads, search, members, and activity are all first-class resources under https://scribe.skeptrune.com/api. The full interactive reference is generated from the same OpenAPI 3.1 spec the server serves at /openapi.json — browse it in the API reference tab.

Authentication

Two credential types, checked in this order:
API keys are org-scoped agent credentials of the form scrb_agt_.... Mint one in Settings → API keys in the app (or via POST /api/org/api-keys, which requires an admin session). The secret token is shown exactly once at creation — only a hash is stored.
Keys carry an access level — read, comment, or edit — and can be given an expiry. Each key acts through its own agent identity — a first-class member of the organization (named after the key, like nick-claude) that can own documents, author comments and suggestions, and appears in activity feeds with an agent badge. An edit key can do everything a member can in the document domain — create and manage docs, folders, shares, threads, and even further API keys — while account administration (profile, org settings, members, invites) remains session-only. A comment key sits between the two: it can read and search, and create comment/suggestion threads, replies, and resolve/reopen them, but cannot edit document content, manage docs, folders, or shares, or accept/reject suggestions (those mutate the document). A read key can only read and search.Some endpoints (membership, sharing, threads, key management itself) require a human actor and reject API keys with a 401 user_session_required error. Each operation’s reference page lists which credentials it accepts.

Errors

Every non-2xx response has the same envelope:
code is a stable machine-readable value: validation_error, unauthorized, user_session_required, forbidden, not_found, conflict, version_gone, stale_version, payload_too_large, unsupported_media_type, or internal_error. message is a human-readable explanation and may change; branch on code.

Writing content converges into live editors

The flagship example of API-first design: PUT /api/docs/{id}/content takes raw text/markdown (up to 4 MB) and applies it through the document’s collaborative session, not around it.
The server diffs the new markdown against the live document and applies the change as an incremental update. Everyone with the document open sees the API’s edit appear in real time, their cursors survive, and anything they type concurrently merges instead of being clobbered. A bot updating a status doc and a human editing it at the same moment is a supported, conflict-free case. Reading is symmetric: GET /api/docs/{id}/content returns the current text/markdown — including edits made seconds ago in someone’s browser.

Concurrent editing & conflict resolution

Agents editing over the API while humans type in the browser is the designed-for case. The API is optimistic — no locks — and merges are conflict-free, so nobody’s keystrokes are lost.
  1. GET returns a version token. GET /api/docs/{id}/content sets an X-Doc-Version response header (mirrored as a quoted ETag) naming the exact document state you received.
  2. PATCH merges your edit. PATCH /api/docs/{id}/content takes your edited markdown as text/markdown plus the required X-Base-Version header (the token from step 1). The server forks the document at your base version, diffs your markdown against that snapshot, and merges only your changes into the live document. Edits humans made since your GET merge in alongside yours instead of being overwritten. The response — {"merged": true, "wordCount": ..., "charCount": ..., "version": "..."} — includes the new version token, so consecutive edits can chain without re-GETting.
  3. Recovery loop. Version tokens are ephemeral (roughly the last 15 writes, at most 24 hours, and they don’t survive server restarts). If your base has expired, PATCH fails with 409 version_gone: re-GET the content, reapply your edit to the fresh markdown, and PATCH again with the new token. Because merges are conflict-free, one retry always suffices.
PUT /content stays a full replace and remains unconditional by default. To guard a replace against concurrent edits, send If-Match (the quoted ETag) or X-Base-Version: if the document changed since that version, the PUT fails with 412 stale_version and writes nothing — re-GET, or switch to PATCH if a merge is what you actually want.

Conventions

  • Base URL: https://scribe.skeptrune.com — all operation paths in the reference are relative to it.
  • Formats: JSON everywhere, except document content, which is text/markdown.
  • Timestamps: epoch milliseconds.
  • Activity: every mutation — human or API key — lands in the activity feed with its actor, so automation stays auditable.