Update Document
Updates a document by uploading a new file, then re-indexes it. This is the canonical endpoint for file-based document updates. Track progress with the returned
batch ID via Get Document Indexing Status.1 min read
patch/datasets/{dataset_id}/documents/{document_id}
Request example
curl --request PATCH \
--url https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'data={"doc_form":"text_model","doc_language":"English","process_rule":{"mode":"automatic"}}' \
--form 'file=<file>'import requests
url = "https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id}"
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "multipart/form-data",
}
files = {
"data": (None, "{\"doc_form\":\"text_model\",\"doc_language\":\"English\",\"process_rule\":{\"mode\":\"automatic\"}}"),
"file": (None, "<file>"),
}
response = requests.request("PATCH", url, headers=headers, files=files)
print(response.text)const form = new FormData();
form.append('data', '{"doc_form":"text_model","doc_language":"English","process_rule":{"mode":"automatic"}}');
form.append('file', '<file>');
const response = await fetch('https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id}', {
method: 'PATCH',
headers: {
'Authorization': 'Bearer <token>',
'Content-Type': 'multipart/form-data'
},
body: form
});
const data = await response.json();
console.log(data);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id}',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_POSTFIELDS => ['data' => '{"doc_form":"text_model","doc_language":"English","process_rule":{"mode":"automatic"}}', 'file' => '<file>'],
CURLOPT_HTTPHEADER => [
'Authorization: Bearer <token>',
'Content-Type: multipart/form-data',
],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
url := "https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id}"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n{\"doc_form\":\"text_model\",\"doc_language\":\"English\",\"process_rule\":{\"mode\":\"automatic\"}}\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<file>\r\n-----011000010111000001101001--\r\n")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id}"))
.header("Authorization", "Bearer <token>")
.header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001")
.method("PATCH", HttpRequest.BodyPublishers.ofString("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n{\"doc_form\":\"text_model\",\"doc_language\":\"English\",\"process_rule\":{\"mode\":\"automatic\"}}\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<file>\r\n-----011000010111000001101001--\r\n"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());require 'uri'
require 'net/http'
url = URI('https://api.dify.ai/v1/datasets/{dataset_id}/documents/{document_id}')
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = url.scheme == 'https'
request = Net::HTTP::Patch.new(url)
request['Authorization'] = 'Bearer <token>'
request['Content-Type'] = 'multipart/form-data'
request.set_form([['data', '{"doc_form":"text_model","doc_language":"English","process_rule":{"mode":"automatic"}}'], ['file', '<file>']], "multipart/form-data")
response = http.request(request)
puts response.read_bodyResponse
{
"batch": "20250306150245647595",
"document": {
"archived": false,
"created_at": 1741267200,
"created_by": "ad313dd6-ef04-4dd1-a5b0-c0f0b9e2e7e4",
"created_from": "api",
"data_source_detail_dict": {
"upload_file": {
"created_at": 1741267200,
"created_by": "ad313dd6-ef04-4dd1-a5b0-c0f0b9e2e7e4",
"extension": "txt",
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"mime_type": "text/plain",
"name": "guide.txt",
"size": 2048
}
},
"data_source_info": {
"upload_file_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"data_source_type": "upload_file",
"dataset_process_rule_id": "e1f2a3b4-c5d6-7890-ef12-345678901234",
"disabled_at": null,
"disabled_by": null,
"display_status": "available",
"doc_form": "text_model",
"doc_metadata": [],
"enabled": true,
"error": null,
"hit_count": 0,
"id": "a8e0e5b5-78c6-4130-a5ce-25feb0e0b4ac",
"indexing_status": "completed",
"name": "guide.txt",
"need_summary": false,
"position": 1,
"summary_index_status": null,
"tokens": 512,
"word_count": 350
}
}{
"code": "filename_not_exists_error",
"message": "The specified filename does not exist.",
"status": 400
}{
"code": "invalid_param",
"message": "Document is not available",
"status": 400
}{
"code": "provider_not_initialize",
"message": "No valid model provider credentials found. Please go to Settings -> Model Provider to complete your provider credentials.",
"status": 400
}{
"code": "too_many_files",
"message": "Only one file is allowed.",
"status": 400
}{
"code": "forbidden",
"message": "Dataset api access is not enabled.",
"status": 403
}{
"code": "forbidden",
"message": "The capacity of the vector space has reached the limit of your subscription.",
"status": 403
}{
"code": "forbidden",
"message": "Sorry, you have reached the knowledge base request rate limit of your subscription.",
"status": 403
}{
"code": "forbidden",
"message": "The API key is not authorized to access this knowledge base.",
"status": 403
}{
"code": "not_found",
"message": "Dataset not found.",
"status": 404
}{
"code": "not_found",
"message": "Document not found.",
"status": 404
}{
"code": "file_too_large",
"message": "File size exceeded.",
"status": 413
}{
"code": "unsupported_file_type",
"message": "File type not allowed.",
"status": 415
}{
"code": "service_unavailable",
"message": "Unable to verify vector space usage right now. Please try again later.",
"status": 503
}patch/datasets/{dataset_id}/documents/{document_id}
Authorization
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, from List Knowledge Bases. For a scoped key, copy the ID from the Dify URL.
Document ID. From List Documents.
Body
multipart/form-dataJSON string containing configuration. Accepts the same fields as Create Document by Text (
doc_form, doc_language, process_rule, retrieval_model, embedding_model, embedding_model_provider) except name and text.File to upload, capped at 15 MB by default.
Self-hosted deployments adjust the limit with the UPLOAD_FILE_SIZE_LIMIT environment variable. On Dify Cloud, Professional and Team plans raise the cap to 50 MB.
Responses
application/json
Document updated successfully.
Batch ID for tracking indexing progress.
Show child attributesHide child attributes
Whether the document is archived.
Creation timestamp (Unix epoch in seconds).
ID of the user who created the document.
Origin of the document.
api for API creation, web for UI creation.Detailed data source information including file details.
Raw data source information, varies by
data_source_type.How the document was created.
upload_file for file uploads, notion_import for Notion imports.ID of the processing rule applied to this document.
Timestamp when the document was disabled.
null if enabled.ID of the user who disabled the document.
null if enabled.User-facing display status derived from
indexing_status and enabled state.Document chunking mode.
text_model for standard text chunking, hierarchical_model for parent-child structure, qa_model for QA pair extraction.Metadata values assigned to this document.
Whether the document is enabled for retrieval.
Error message if indexing failed.
null when no error.Number of times the document has been matched in retrieval queries.
Unique identifier of the document.
Current indexing status.
waiting for queued, parsing while extracting content, cleaning while removing noise, splitting while chunking, indexing while building vectors, completed when ready, error if failed, paused if manually paused.Document name.
Whether a summary needs to be generated for this document.
Display position of the document in the list.
Status of the summary index for this document.
null if summary indexing is not configured.Total number of tokens in the document.
Total word count of the document.