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, and block_annotations / block_enhance_settings (if the document has them) must be sent back too, otherwise they are permanently removed. First read the current content with GET /documents/:id, modify it, and send it all back.

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

You normally do not author these by hand - read them from the GET /documents/:id response and send them back unchanged when updating. Both fields are validated; a malformed structure returns 400 VALIDATION_ERROR.

⚠️ Warning: updating content replaces the whole content. If you omit block_annotations or block_enhance_settings, the annotations and screenshot styling are permanently removed.


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.