Update Document Metadata
Merges keys into a document’s user_metadata and returns the updated document. Unlike the other operations on this path, it takes the document ID, not a document file ID.
Send the document’s row_version as expectedRowVersion. Read the document right before updating it, and on 409 read it again and resend.
curl --request PATCH \
--url https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expectedRowVersion": 4,
"patch": {
"owner": "billing-team",
"review_date": "2027-03-01T00:00:00Z"
}
}
'import requests
url = "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}"
payload = {
"expectedRowVersion": 4,
"patch": {
"owner": "billing-team",
"review_date": "2027-03-01T00:00:00Z"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
expectedRowVersion: 4,
patch: {owner: 'billing-team', review_date: '2027-03-01T00:00:00Z'}
})
};
fetch('https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'expectedRowVersion' => 4,
'patch' => [
'owner' => 'billing-team',
'review_date' => '2027-03-01T00:00:00Z'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}"
payload := strings.NewReader("{\n \"expectedRowVersion\": 4,\n \"patch\": {\n \"owner\": \"billing-team\",\n \"review_date\": \"2027-03-01T00:00:00Z\"\n }\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expectedRowVersion\": 4,\n \"patch\": {\n \"owner\": \"billing-team\",\n \"review_date\": \"2027-03-01T00:00:00Z\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expectedRowVersion\": 4,\n \"patch\": {\n \"owner\": \"billing-team\",\n \"review_date\": \"2027-03-01T00:00:00Z\"\n }\n}"
response = http.request(request)
puts response.read_body{
"active": {
"activated_at": "2026-10-20T08:16:05Z",
"content_hash": "4f7c2d9a1b3e5f60718293a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4",
"created_at": "2026-10-20T08:15:42Z",
"document_asset_id": "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b",
"document_asset_version": 1,
"document_id": "2f6b8d1a-7c3e-4a5b-9d0e-1f2a3b4c5d6e",
"knowledge_space_id": "9b2e5b7a-3c1d-4e2f-8a9b-1c2d3e4f5a6b",
"mime_type": "application/pdf",
"revision": 2,
"size_bytes": 482113,
"state": "active"
},
"active_revision": 2,
"created_at": "2026-09-03T10:02:11Z",
"disabled_at": null,
"disabled_by_subject_id": null,
"enabled": true,
"id": "2f6b8d1a-7c3e-4a5b-9d0e-1f2a3b4c5d6e",
"knowledge_space_id": "9b2e5b7a-3c1d-4e2f-8a9b-1c2d3e4f5a6b",
"latest_task": null,
"provider_item_id": null,
"row_version": 5,
"source_id": null,
"status": "ready",
"title": "handbook.pdf",
"updated_at": "2026-10-21T02:40:13Z",
"user_metadata": {
"owner": "billing-team",
"product_line": "billing",
"review_date": "2027-03-01T00:00:00Z"
}
}Authorizations
Every request authenticates with an API key: Authorization: Bearer {API_KEY}. App endpoints take an app API key; knowledge endpoints take a knowledge base API key (Get Started).
Keep keys server-side; never embed them in client code. Requests with a missing or invalid key fail with HTTP 401 (unauthorized).
Path Parameters
Knowledge base ID: the last segment of the Service API endpoint shown in the knowledge base's API Access dialog (…/knowledge-fs/spaces/<knowledge base ID>), and the segment after /datasets/new/ in the address bar.
The document ID: id from List Documents or Get Document, or document_id from Get Document by File. Not a document file ID, even though Get Document File and Delete Document File take one on this path. A document file ID answers 404.
Body
The normalized request must fit within 131,072 UTF-8 bytes. See Request Size Limits.
The document's current row_version, from Get Document or List Documents, or the row_version this operation last returned. A newly active revision and enabling or disabling the document in Dify also change it, so read it right before updating. A stale value answers 409 and nothing changes.
x >= 0Keys to merge into user_metadata:
- A key with a value sets that key.
- A key with
nullremoves it. - Keys you leave out stay as they are.
Each key names a metadata field, in lowercase snake case. The field must already exist: create it in Dify first. The value must match the field's type: a string for string, a finite number for number, and a UTC timestamp such as 2026-12-01T00:00:00Z for time.
Reserved keys answer 400: activeRevision, contentHash, documentAssetId, documentAssetVersion, mimeType, provenance, providerItemId, sourceId, system, systemMetadata, tenantId, __knowledgeFs, and keys starting with system., provenance., or __knowledgeFs..
Response
The updated document. Its row_version is the value to send on the next update, and latest_task is always null in this response.
The active revision: the content the knowledge base serves. Pass its revision to List Chunks and its document_asset_id to Get Document File. null while no revision is active.
Show child attributes
Show child attributes
Number of the active revision. null while none is active.
When the document was created, ISO 8601.
When the document was disabled in Dify, ISO 8601.
Internal ID of whoever disabled the document. Not needed to call this API.
false after the document is disabled in Dify. Re-index Documents skips disabled documents.
Document ID. It stays the same when the document's content is updated.
Internal ID of the knowledge base. Not the knowledge base ID in the path.
The newest indexing task behind the document's revisions, with task_kind: document. Follow it with Get Document Indexing Task using its id. null when there is none, and always null in the Update Document Metadata response.
Show child attributes
Show child attributes
For a document imported from a source, the item's identifier there: the providerItemId sent to Import Source Items, or the page_id of a website page.
Change counter. Send it as expectedRowVersion on Update Document Metadata, and as expectedRevision on Delete Document. It increases on metadata updates, when a new revision becomes active or the active revision's file is deleted, when the document's source is deleted with documents=keep, and when the document is enabled or disabled in Dify.
Source the document came from. null for uploaded files.
pending (no revision active yet), ready (a revision is active), failed (the first revision failed to index and none is active), or deleting. A ready document stays ready when a later revision fails.
Document title.
When the document last changed, ISO 8601.
Custom metadata, keyed by metadata field name. Change it with Update Document Metadata or in Dify.
Was this page helpful?
curl --request PATCH \
--url https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expectedRowVersion": 4,
"patch": {
"owner": "billing-team",
"review_date": "2027-03-01T00:00:00Z"
}
}
'import requests
url = "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}"
payload = {
"expectedRowVersion": 4,
"patch": {
"owner": "billing-team",
"review_date": "2027-03-01T00:00:00Z"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
expectedRowVersion: 4,
patch: {owner: 'billing-team', review_date: '2027-03-01T00:00:00Z'}
})
};
fetch('https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'expectedRowVersion' => 4,
'patch' => [
'owner' => 'billing-team',
'review_date' => '2027-03-01T00:00:00Z'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}"
payload := strings.NewReader("{\n \"expectedRowVersion\": 4,\n \"patch\": {\n \"owner\": \"billing-team\",\n \"review_date\": \"2027-03-01T00:00:00Z\"\n }\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expectedRowVersion\": 4,\n \"patch\": {\n \"owner\": \"billing-team\",\n \"review_date\": \"2027-03-01T00:00:00Z\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{api_base_url}/knowledge-fs/spaces/{knowledge_base_id}/documents/{document_file_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expectedRowVersion\": 4,\n \"patch\": {\n \"owner\": \"billing-team\",\n \"review_date\": \"2027-03-01T00:00:00Z\"\n }\n}"
response = http.request(request)
puts response.read_body{
"active": {
"activated_at": "2026-10-20T08:16:05Z",
"content_hash": "4f7c2d9a1b3e5f60718293a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4",
"created_at": "2026-10-20T08:15:42Z",
"document_asset_id": "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b",
"document_asset_version": 1,
"document_id": "2f6b8d1a-7c3e-4a5b-9d0e-1f2a3b4c5d6e",
"knowledge_space_id": "9b2e5b7a-3c1d-4e2f-8a9b-1c2d3e4f5a6b",
"mime_type": "application/pdf",
"revision": 2,
"size_bytes": 482113,
"state": "active"
},
"active_revision": 2,
"created_at": "2026-09-03T10:02:11Z",
"disabled_at": null,
"disabled_by_subject_id": null,
"enabled": true,
"id": "2f6b8d1a-7c3e-4a5b-9d0e-1f2a3b4c5d6e",
"knowledge_space_id": "9b2e5b7a-3c1d-4e2f-8a9b-1c2d3e4f5a6b",
"latest_task": null,
"provider_item_id": null,
"row_version": 5,
"source_id": null,
"status": "ready",
"title": "handbook.pdf",
"updated_at": "2026-10-21T02:40:13Z",
"user_metadata": {
"owner": "billing-team",
"product_line": "billing",
"review_date": "2027-03-01T00:00:00Z"
}
}