Documents
Endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /documents | documents:read | List documents |
| POST | /documents | documents:write | Create a document |
| GET | /documents/:id | documents:read | Get a document with content |
| PATCH | /documents/:id | documents:write | Update a document |
| DELETE | /documents/:id | documents:write | Soft-delete a document |
List Documents
curl "https://my.clarife.app/api/v1/documents?limit=10&offset=0" \
-H "Authorization: Bearer clrf_your_key"Query parameters:
| Param | Type | Default | Description |
|---|---|---|---|
| limit | integer | 50 | Results per page (1-100) |
| offset | integer | 0 | Number of results to skip |
| sort | string | updated_at | Sort field: updated_at, created_at, title |
| order | string | desc | Sort order: asc or desc |
| project_id | uuid | -- | Filter by project |
Response:
{
"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
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:
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | No | Document title (max 500 chars, defaults to "Untitled") |
| description | string | No | Short description (max 2000 chars) |
| content | object | No | Document content (see Content Format below) |
| project_id | uuid | No | Assign to a project |
| template | string | No | Template identifier |
| visibility | string | No | private or workspace (requires X-Workspace-Id header) |
Response (201 Created):
{
"data": {
"id": "d2b3c4d5-6789-01ab-cdef-2345678901ab",
"title": "API Setup Guide",
"created_at": "2026-03-28T12:00:00Z"
}
}Get a Document
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:
{
"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
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.
| Field | Type | Description |
|---|---|---|
| title | string | New title (max 500 chars) |
| description | string | New description (max 2000 chars) |
| content | object | Replace document content |
| expected_version | integer | Optional 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):
{
"data": {
"id": "d1a2b3c4-...",
"title": "Updated Title",
"version": 5,
"updated_at": "2026-03-28T13:00:00Z"
}
}Delete a Document
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:
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Block type (see types below) |
| id | string | Yes | Unique ID within the document (e.g. "h1-title", "ss3-result") |
| sort_order | integer | Yes | Display order starting from 0 |
heading
{
"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
{
"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
{
"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 workflowcaption(string, optional): displayed below the imagealignment:"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
{ "type": "divider", "id": "d1", "sort_order": 5 }No additional fields.
code
{
"type": "code",
"id": "c1-example",
"sort_order": 6,
"code": "npm install clarife",
"language": "bash"
}code(required): the code stringlanguage: syntax highlighting (e.g."python","javascript","bash","sql")
table
{
"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 rowcolumns(required): one entry per column;labelis the header text, optionalwidth(px) andalign("left"|"center"|"right")rows: 2D array of cell strings - data only, headers live incolumns
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 blockidblock_enhance_settings: screenshot frame and background styling, also keyed by blockid
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:
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.