Documents

Update a document

Updates document content, title, path, metadata, or tags. Supplying path moves the document to a new logical path within the project.

patch/v1/projects/{project_id}/documents/{document_id}

Request

  • Base URL: https://api.naturali.ai
  • URL: https://api.naturali.ai/v1/projects/{project_id}/documents/{document_id}
  • Auth: one of:
    • HTTP bearer
    • OAuth 2 (authorization code, authorization URL https://api.naturali.ai/authorize, token URL https://api.naturali.ai/token, scopes: mcp:access)

Path parameters

document_idstring required
Example:doc_V1StGXR8Z5jdHi6B

Document ID

Headers

If-Matchstring

The version the caller believes the resource holds, as an entity tag (3 or "3"). Equivalent to expected_version in the request body; * states no precondition beyond the resource existing. A mismatch is 409 VERSION_CONFLICT.

Request body

contentstring

New text content

titlestring

New title

pathstring nullable

Logical path within the project (e.g. /reports/q1.txt). Pass null to clear.

metadataNullableMetadataBag nullable

A MetadataBag on a request field where null is meaningful: a full-replacement update that clears the bag. A record whose bag is unset leaves the field out.

tagsTagBag

Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with 400 VALIDATION_FAILED, never coerced. Keys are opaque and stored verbatim, so cost_center and costCenter are two different tags. Matched by JSONB containment wherever tags are read: the ?tags= filter and knowledge search.

Keys beginning system. are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with 400 RESERVED_TAG_KEY. They are read and filtered like any other tag.

The bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is 400 VALIDATION_FAILED with meta.limit naming the bound it crossed. system.* keys are the platform's and do not count against the 50.

expected_versioninteger nullable

The version the caller believes the resource holds. When the resource is at any other version the write is refused with 409 VERSION_CONFLICT and nothing is written; meta.current_version on that response names the version in force.

Omit it to write unconditionally. Omitting it does not make the write unordered: two writes that reach the server together are still serialized, and the one whose version was taken first is refused the same way. What the field adds is refusing a write whose author read the resource some time ago and has not seen what happened since.

The If-Match header carries the same precondition for a client that prefers the HTTP spelling. Sending both with different versions is 400 VALIDATION_FAILED.

Example request

{
  "path": "/reports/q1.txt",
  "metadata": {
    "author": "John",
    "revision": 2
  },
  "tags": {
    "team": "finance",
    "env": "prod"
  },
  "expected_version": 3
}

Response

Document updated

idstring

Document ID

file_idstring

Underlying file ID

project_idstring

Project ID

pathstring nullable

Logical path of the document within the project (e.g. /reports/q1.txt)

filenamestring

Original filename

content_typestring

Media type of the source file the document was ingested from. Absent when the underlying file is gone.

sizeinteger

File size in bytes

status'pending' | 'processing' | 'ready' | 'failed' | 'withdrawn'

Ingestion lifecycle state. pending — enqueued; processing — chunks being extracted and embedded; ready — fully indexed; failed — processing error (see the error field on GET /documents/{id}/status); withdrawn — taken out of listings and search, with its chunks dropped, and restorable from an earlier version.

versioninteger

The document's content version, starting at 1. Every write that changes the content or its annotations archives the state it replaced and increments this.

contentstring nullable

Text content (only present on getDocument, and only when status is ready)

chunk_strategy'page' | 'whole' | 'size'

The chunk strategy the document was last (re-)ingested with. Absent when the default (whole) was used — the mapper omits the key rather than sending null.

chunk_sizeinteger

Window size in characters used when chunk_strategy=size. Absent otherwise.

chunk_overlapinteger

Overlap in characters between consecutive windows used when chunk_strategy=size. Absent otherwise.

created_atstring date-time
updated_atstring date-time

Example response

{
  "id": "doc_V1StGXR8Z5jdHi6B",
  "file_id": "file_V1StGXR8Z5jdHi6B",
  "project_id": "proj_V1StGXR8Z5jdHi6B",
  "path": "/reports/q1.txt",
  "filename": "my-doc.txt",
  "content_type": "application/pdf",
  "size": 42,
  "status": "ready",
  "version": 1,
  "content": "The quick brown fox jumps over the lazy dog.",
  "chunk_strategy": "size",
  "chunk_size": 800,
  "chunk_overlap": 120
}

Changes

No recorded changes to this operation across all 1 revision of this API.