Documents

Documents belong to a workspace, optionally live inside a folder, and go through an async ingestion pipeline (parsingembeddingindexed, or failed). Access to a document's contents is enforced inside the vector query itself, not filtered afterward — a restricted document still shows up in listings (existence is visible, Drive-style), but only a caller in its ACL group can retrieve chunks or citations from it.

Upload document

Upload a file (multipart) and enqueue it for ingestion.

POST /api/v1/workspaces/{workspace_id}/documents · Auth: JWT, documents.upload

Request body

Content type: multipart/form-data.

ParameterTypeRequiredDescription
filefileYesThe document file to upload.
folder_idstring (uuid)NoTarget folder. Omit to upload into the workspace root.

Sample request

curl -sX POST https://ragz.example.com/api/v1/workspaces/$WORKSPACE_ID/documents \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@employee-handbook.pdf" \
  -F "folder_id=9f8e...-uuid"

Sample response

{
  "id": "d1e2...-uuid",
  "workspace_id": "a1b2...-uuid",
  "filename": "employee-handbook.pdf",
  "status": "parsing",
  "folder_id": "9f8e...-uuid",
  "acl_group_ids": null,
  "pinned": false,
  "approved": false,
  "version": 1
}

Response fields

FieldTypeDescription
idstring (uuid)Document id.
workspace_idstring (uuid)Workspace the document belongs to.
filenamestringOriginal filename.
statusstringIngestion status — starts parsing, moves through embedding to indexed, or failed.
folder_idstring (uuid) | nullFolder the document was uploaded into.
acl_group_idsarray | nullACL group ids restricting the document. Admin/superadmin-only metadata — blanked to null for plain members, even for their own uploads.
pinnedbooleanWhether the document is pinned.
approvedbooleanWhether this version is approved.
versionintegerDocument version number.

Notes

  • The response's status starts as the document enters the ingestion queue — poll GET /workspaces/{id}/documents (or your workspace's document list in the UI) to watch it move to indexed.
  • acl_group_ids is admin-only metadata: a plain member gets null here even for their own uploads, unless they hold admin/superadmin.

Upload size limits

Uploads route through two size caps depending on where they're sent from: the general document upload endpoint above enforces the platform's max_upload_mb setting (100 MB by default); the chat attachment endpoint (POST /chats/{id}/attachments, see Chat) uses the smaller interactive upload cap — 50 MB by default (interactive_upload_mb), since attachments block an in-progress chat turn. Both return 413 Payload Too Large over the limit.


List documents

List documents in a workspace.

GET /api/v1/workspaces/{workspace_id}/documents · Auth: JWT, documents.list

Query parameters

ParameterTypeRequiredDescription
folder_idstring (uuid)NoFilter to documents inside a specific folder.

Notes

  • Returns an array of document objects, same shape as the Upload document response above.

Get document file

Stream the original file bytes (citation viewer).

GET /api/v1/documents/{document_id}/file · Auth: JWT, documents.content.read


Delete document

Delete a document. Deletion is asynchronous — the route flips the document to deleting and returns 202 immediately; a worker propagates the removal to storage and the vector index.

DELETE /api/v1/documents/{document_id} · Auth: JWT, documents.delete

Sample request

curl -sX DELETE https://ragz.example.com/api/v1/documents/$DOCUMENT_ID \
  -H "Authorization: Bearer $TOKEN"

Sample response

202 Accepted

{ "status": "deletion scheduled" }

Response fields

FieldTypeDescription
statusstringAlways "deletion scheduled".

Notes

  • Deletion is asynchronous — the route flips the document to deleting and returns 202 immediately; a worker propagates the removal to storage and the vector index.

Reindex document

Re-run the parse→chunk→embed pipeline for one document, without a re-upload — useful after a parser or embedding-model change.

POST /api/v1/documents/{document_id}/reindex · Auth: JWT, documents.upload

Notes

  • Only accepts documents currently in indexed or failed state — a document mid-ingest can't be reindexed out from under itself.

Pin document

Pin/unpin a document.

PATCH /api/v1/documents/{document_id}/pin · Auth: JWT, documents.pin


Move document

Move a document to a different folder.

PATCH /api/v1/documents/{document_id}/move · Auth: JWT, documents.move


Set document ACL

Set the ACL group ids restricting a document.

PUT /api/v1/documents/{document_id}/acl · Auth: JWT, documents.acl.manage

Notes

  • An empty/null list means unrestricted (any workspace member).
  • Admin-only (documents.acl.manage).

Approve document

Approve/unapprove a document version.

PUT /api/v1/documents/{document_id}/approved · Auth: JWT, documents.approve


Set document metadata

Set custom metadata field values.

PUT /api/v1/documents/{document_id}/metadata · Auth: JWT, documents.metadata.update


Create folder

Create a folder.

POST /api/v1/workspaces/{workspace_id}/folders · Auth: JWT, folders.create


Ensure folder path

Create a full folder path if missing.

POST /api/v1/workspaces/{workspace_id}/folders/ensure-path · Auth: JWT, folders.create


List folders

List folders in a workspace.

GET /api/v1/workspaces/{workspace_id}/folders · Auth: JWT, folders.read


Update folder

Rename/move a folder.

PATCH /api/v1/folders/{folder_id} · Auth: JWT, folders.update


Preview folder delete

Preview what a folder delete would cascade to.

GET /api/v1/folders/{folder_id}/delete-preview · Auth: JWT, folders.delete

Notes

  • Reports the document and subfolder counts before you commit to the delete.

Delete folder

Delete a folder and cascade-delete its contents.

DELETE /api/v1/folders/{folder_id} · Auth: JWT, folders.delete

Notes

  • Deleting a folder cascades to every document and subfolder beneath it.
  • Each document's own ACL is still individually enforced during that cascade — not bypassed by the folder-level delete.

List metadata fields

List the workspace's custom metadata field schema.

GET /api/v1/workspaces/{workspace_id}/metadata-fields · Auth: JWT, documents.list


Create metadata field

Define a custom metadata field.

POST /api/v1/workspaces/{workspace_id}/metadata-fields · Auth: JWT, workspace.metadata.manage


Delete metadata field

Remove a metadata field.

DELETE /api/v1/metadata-fields/{field_id} · Auth: JWT, workspace.metadata.manage