API reference
18 operations in documents. Raw spec: openapi.json.
GET
/api/v1/documentsGET /api/documents
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
q | query | — | No | Title substring narrowing; ranked full-text search rides /api/search. |
client_id | query | — | No | Scope narrow: a client uuid, or the literal `global` for org-wide documents (docs-platform v1). Absent = all scopes. |
layout_id | query | — | No |
Responses
| Status | Description |
|---|---|
200 |
Security: bearer
POST
/api/v1/documentsPOST /api/documents — instant-first (IF1/IF2); creates the document and its immutable version 1 in one commit.
Request body
CreateDocumentRequest
Responses
| Status | Description |
|---|---|
200 | |
409 | idempotency key reused |
422 | title/body rejected by document rules |
Security: bearer
GET
/api/v1/documents/layoutsGET /api/documents/layouts — the org's layout catalog (system first).
Responses
| Status | Description |
|---|---|
200 |
Security: bearer
POST
/api/v1/documents/layoutsPOST /api/documents/layouts — instant-first; system slugs are reserved.
Request body
CreateLayoutRequest
Responses
| Status | Description |
|---|---|
200 | |
409 | idempotency key reused or slug taken |
422 | invalid field schema |
Security: bearer
PATCH
/api/v1/documents/layouts/{id}PATCH /api/documents/layouts/{id} — instant-first; system layouts are editable (schema and branding), never deletable.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Request body
UpdateLayoutRequest
Responses
| Status | Description |
|---|---|
200 | |
404 | layout not visible in scope |
Security: bearer
DELETE
/api/v1/documents/layouts/{id}DELETE /api/documents/layouts/{id} — custom layouts only; system layouts are a typed 409 (imports and the DMS seam rely on them).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | deleted |
404 | layout not visible in scope |
409 | system layouts cannot be deleted |
Security: bearer
DELETE
/api/v1/documents/links/{id}DELETE /api/documents/links/{id}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | deleted |
404 | link not visible in scope |
Security: bearer
GET
/api/v1/documents/{id}GET /api/documents/{id}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | |
404 | document not visible in scope |
Security: bearer
PATCH
/api/v1/documents/{id}PATCH /api/documents/{id} — instant-first (IF1/IF2); an edit APPENDS the next immutable version and moves the document's head to it. No existing version row is touched.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Request body
UpdateDocumentRequest
Responses
| Status | Description |
|---|---|
200 | |
404 | document not visible in scope |
409 | version conflict or idempotency key reused |
422 | title/body rejected by document rules |
Security: bearer
GET
/api/v1/documents/{id}/attachmentsGET /api/documents/{id}/attachments — newest-first list for one doc.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 |
Security: bearer
POST
/api/v1/documents/{id}/attachmentsPOST /api/documents/{id}/attachments — raw octet-stream upload (same header contract as the ticket surface: `x-filename` + declared content-type verified against sniffed magic bytes).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Request body
array<integer>
Responses
| Status | Description |
|---|---|
200 | |
404 | document not visible in scope |
422 | validation failed |
Security: bearer
DELETE
/api/v1/documents/{id}/attachments/{attachment_id}DELETE /api/documents/{id}/attachments/{attachment_id} — author-gated (the uploader, or an org owner/admin). The stored object is reclaimed only when NO row in EITHER attachments table still references the same content-addressed key.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | |
attachment_id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | |
404 | attachment not visible in scope |
Security: bearer
GET
/api/v1/documents/{id}/attachments/{attachment_id}/downloadGET /api/documents/{id}/attachments/{attachment_id}/download — streams the stored object behind documents authz, or answers with a presigned URL when the caller asks for one (`?presign=true`) and the store can sign it.
Same rule as the ticket attachment door: the stream is the contract and the ticket is the optimisation, and no URL is minted for an object whose scan verdict has not been read and admitted.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | |
attachment_id | path | string | Yes | |
presign | query | boolean | No | `true` asks for a download ticket instead of the bytes; the answer says whether a URL was minted |
Responses
| Status | Description |
|---|---|
200 | |
409 | the object is held by the scan gate: neither a URL nor the bytes are issued |
Security: bearer
GET
/api/v1/documents/{id}/linksdocuments_list_links
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 |
Security: bearer
POST
/api/v1/documents/{id}/linksPOST /api/documents/{id}/links — target existence is enforced by the resolution join (the link row itself allows any uuid, so the route checks the target kind's table exists for the org before insert).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Request body
CreateLinkRequest
Responses
| Status | Description |
|---|---|
200 | |
404 | document or link target not visible in scope |
409 | link already exists |
Security: bearer
POST
/api/v1/documents/{id}/restorePOST /api/documents/{id}/restore — instant-first (IF1/IF2); §6 rule: the restore APPENDS a new version copying the target's content. The target's title comes along, renames after it are not silently undone.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Request body
RestoreDocumentRequest
Responses
| Status | Description |
|---|---|
200 | |
404 | document or restore target not visible in scope |
409 | version conflict or idempotency key reused |
422 | restore rejected by document rules |
Security: bearer
GET
/api/v1/documents/{id}/versionsGET /api/documents/{id}/versions — the full immutable history, newest first, complete bodies included so any pair is diffable.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | |
404 | document not visible in scope |
Security: bearer
GET
/api/v1/documents/{id}/versions/{version}GET /api/documents/{id}/versions/{version} — one immutable snapshot.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | |
version | path | integer | Yes |
Responses
| Status | Description |
|---|---|
200 | |
404 | document or version not visible in scope |
Security: bearer