Documents

Endpoints

MethodPathScopeDescription
GET/documentsdocuments:readList documents
POST/documentsdocuments:writeCreate a document
GET/documents/:iddocuments:readGet a document with content
PATCH/documents/:iddocuments:writeUpdate a document
DELETE/documents/:iddocuments:writeSoft-delete a document

List Documents

bash
curl "https://my.clarife.app/api/v1/documents?limit=10&offset=0" \
  -H "Authorization: Bearer clrf_your_key"

Query parameters:

ParamTypeDefaultDescription
limitinteger50Results per page (1-100)
offsetinteger0Number of results to skip
sortstringupdated_atSort field: updated_at, created_at, title
orderstringdescSort order: asc or desc
project_iduuid--Filter by project

Response:

json
{
  "data": [
    {
      "id": "d1a2b3c4-5678-90ab-cdef-1234567890ab",
      "title": "Getting Started Guide",
      "description": "Onboarding tutorial for new users",
      "updated_at": "2026-03-20T14:00:00Z",
      "created_at": "2026-03-15T10:30:00Z",
      "block_count": 12,
      "screenshot_count": 5,
      "word_count": 450,
      "visibility": "private"
    }
  ],
  "total": 1,
  "limit": 10,
  "offset": 0
}

Create a Document

bash
curl -X POST https://my.clarife.app/api/v1/documents \
  -H "Authorization: Bearer clrf_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "API Setup Guide",
    "description": "How to connect via the clarife API",
    "project_id": "p1a2b3c4-5678-90ab-cdef-1234567890ab"
  }'

Body parameters:

FieldTypeRequiredDescription
titlestringNoDocument title (max 500 chars, defaults to "Untitled")
descriptionstringNoShort description (max 2000 chars)
contentobjectNoDocument content (see Content Format below)
project_iduuidNoAssign to a project
templatestringNoTemplate identifier
visibilitystringNoprivate or workspace (requires X-Workspace-Id header)

Response (201 Created):

json
{
  "data": {
    "id": "d2b3c4d5-6789-01ab-cdef-2345678901ab",
    "title": "API Setup Guide",
    "created_at": "2026-03-28T12:00:00Z"
  }
}

Get a Document

bash
curl https://my.clarife.app/api/v1/documents/d1a2b3c4-5678-90ab-cdef-1234567890ab \
  -H "Authorization: Bearer clrf_your_key"

Returns the full document including content with all blocks.

Response:

json
{
  "data": {
    "id": "d1a2b3c4-...",
    "title": "Getting Started Guide",
    "description": "Onboarding tutorial",
    "content": {
      "meta": { "version": 1, "locale": "en" },
      "blocks": [
        { "type": "heading", "id": "h1-title", "sort_order": 0, "level": 1, "content": "Getting Started" },
        { "type": "text", "id": "t1-intro", "sort_order": 1, "content": "Welcome to the guide." },
        { "type": "screenshot", "id": "ss1-dashboard", "sort_order": 2, "media_id": "m1234567-...", "caption": "Dashboard view", "alignment": "center" }
      ]
    },
    "version": 4,
    "block_count": 3,
    "screenshot_count": 1,
    "word_count": 12,
    "visibility": "private",
    "template": null,
    "branding_id": null,
    "updated_at": "2026-03-20T14:00:00Z",
    "created_at": "2026-03-15T10:30:00Z"
  }
}

The top-level version field is the document's version number, incremented on every content change - pass it as expected_version when updating (see below).


Update a Document

bash
curl -X PATCH https://my.clarife.app/api/v1/documents/d1a2b3c4-5678-90ab-cdef-1234567890ab \
  -H "Authorization: Bearer clrf_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Updated Title" }'

All body fields are optional. Only provided fields are updated.

FieldTypeDescription
titlestringNew title (max 500 chars)
descriptionstringNew description (max 2000 chars)
contentobjectReplace document content
expected_versionintegerOptional concurrency guard - the version value from GET /documents/:id (mismatch = 409 CONFLICT)

⚠️ Warning: When updating content, you must send the full content - the blocks array replaces the existing one. First read the current content with GET /documents/:id, modify it, and send it all back. The only exception are block_annotations and block_enhance_settings - you can omit them and the server keeps the existing values (see Annotations and screenshot enhance settings below).

Optimistic concurrency (optional): pass the version value from the GET /documents/:id response as expected_version. The update then applies only if the document has not changed in the meantime - otherwise the API returns 409 with code CONFLICT and the current version number in the message. On a conflict, re-read the document, re-apply your changes to the fresh content, and retry. We recommend sending expected_version with every content update - it protects against overwriting changes saved concurrently in the editor, by another integration, or by an MCP agent.

Response (200 OK):

json
{
  "data": {
    "id": "d1a2b3c4-...",
    "title": "Updated Title",
    "version": 5,
    "updated_at": "2026-03-28T13:00:00Z"
  }
}

Delete a Document

bash
curl -X DELETE https://my.clarife.app/api/v1/documents/d1a2b3c4-5678-90ab-cdef-1234567890ab \
  -H "Authorization: Bearer clrf_your_key"

Documents are soft-deleted (moved to trash). They are permanently removed after 30 days.

Response (204 No Content): Empty body.


Content Format

Document content follows a flat block-based structure. Each block must include these common fields:

FieldTypeRequiredDescription
typestringYesBlock type (see types below)
idstringYesUnique ID within the document (e.g. "h1-title", "ss3-result")
sort_orderintegerYesDisplay order starting from 0

heading

json
{
  "type": "heading",
  "id": "h1-title",
  "sort_order": 0,
  "level": 1,
  "content": "My Tutorial Title"
}
  • level: 1, 2, or 3 (H1, H2, H3)
  • content: plain text

text

json
{
  "type": "text",
  "id": "t1-intro",
  "sort_order": 1,
  "content": "Paragraph text here.\nUse line breaks for lists:\n• Item one\n• Item two"
}
  • content: plain text or basic HTML (<b>, <i>, <a>, <br>)

screenshot / image

json
{
  "type": "screenshot",
  "id": "ss1-dashboard",
  "sort_order": 2,
  "media_id": "77b4185f-bb13-47ea-97a4-6b0d88289df1",
  "caption": "Dashboard overview",
  "alignment": "center"
}
  • media_id (UUID, required): references an uploaded media file - see the Media API for the upload workflow
  • caption (string, optional): displayed below the image
  • alignment: "left", "center", or "right"
  • width (integer, optional): display width in pixels (omit for original size)

Use "image" type for non-screenshot visuals (diagrams, illustrations). Same schema as screenshot.

divider

json
{ "type": "divider", "id": "d1", "sort_order": 5 }

No additional fields.

code

json
{
  "type": "code",
  "id": "c1-example",
  "sort_order": 6,
  "code": "npm install clarife",
  "language": "bash"
}
  • code (required): the code string
  • language: syntax highlighting (e.g. "python", "javascript", "bash", "sql")

table

json
{
  "type": "table",
  "id": "tbl1",
  "sort_order": 7,
  "has_header": true,
  "columns": [
    { "label": "Name" },
    { "label": "Role" }
  ],
  "rows": [
    ["Alice", "Developer"],
    ["Bob", "Designer"]
  ]
}
  • has_header (boolean, required): whether the column labels render as a header row
  • columns (required): one entry per column; label is the header text, optional width (px) and align ("left" | "center" | "right")
  • rows: 2D array of cell strings - data only, headers live in columns

Annotations and screenshot enhance settings

Besides meta and blocks, content can carry two optional objects created in the clarife editor:

  • block_annotations: annotation layers (arrows, boxes, blur, etc.) keyed by screenshot block id
  • block_enhance_settings: screenshot frame and background styling, also keyed by block id

Both fields are read-only through the API. When updating a document you can omit them - the server keeps the existing values. You can also send them back exactly as returned by GET /documents/:id. Any new or changed value is rejected with 400 and code ANNOTATIONS_EDITOR_ONLY.

ℹ️ Why: public share and embed pages (and AI videos) show images baked in the clarife editor. The API does not generate baked images, so annotations written through the API would never be visible to readers - and blur or pixelation would not really hide the data underneath. That is why the API rejects these fields instead of accepting content readers would never see. To point at something in a screenshot, describe it in the step text - the document owner can add arrows, step markers, or blur in the editor.


Complete Example

Creating a document with text and a screenshot:

bash
curl -X POST https://my.clarife.app/api/v1/documents \
  -H "Authorization: Bearer clrf_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Setup Guide",
    "content": {
      "meta": { "version": 1, "locale": "en" },
      "blocks": [
        { "type": "heading", "id": "h1", "sort_order": 0, "level": 1, "content": "Setup Guide" },
        { "type": "text", "id": "t1", "sort_order": 1, "content": "Follow these steps to get started." },
        { "type": "screenshot", "id": "ss1", "sort_order": 2, "media_id": "77b4185f-...", "caption": "Settings screen", "alignment": "center" },
        { "type": "divider", "id": "d1", "sort_order": 3 },
        { "type": "text", "id": "t2", "sort_order": 4, "content": "You are all set!" }
      ]
    }
  }'

ℹ️ Info: To add images, you must first upload them via the Media API. The 4-step workflow is: create presigned URL → upload file → confirm → add screenshot block with media_id to the document.