Skip to main content
This API serves agent knowledge bases only. Classic knowledge bases use the Classic Knowledge Base API.
Some work happens only in Dify, such as creating the knowledge base and its metadata fields, uploading files, and enabling or disabling documents.

Get the Knowledge Base’s Endpoint

For the API key and its scope, see Knowledge Base API. Open the knowledge base in Dify, click API Access in the lower-left corner, and copy the endpoint. It ends with /knowledge-fs/spaces/<knowledge base ID>, and that ID is the knowledge_base_id every operation takes.

Query the Knowledge Base

Decide the retrieval depth (mode) first: The script below needs Bash, curl, jq, and Python 3. Copy its two code blocks, in order, into query.sh, run bash query.sh, and when prompted, enter the endpoint you copied and an API key.
1

Create a query token

Call Create Query Token with the question in query and the depth in mode.
2

Run the query

Post request to Run Query unchanged, with the query token in place of the API key and trace_id as the X-Trace-ID header.
Keep the query record ID from the x-query-run-id response header to investigate the answer. It isn’t step 1’s trace_id.
3

Read the events

Treat only answer.done as success. An answer.error can arrive after answer.delta frames, under HTTP 200: discard the partial text. A dropped connection can’t be resumed. After any failure, before or after the stream opens, start again from step 1.Set your client’s read timeout to allow for your slowest depth. Run Query sends no keep-alive events, and a default timeout can cut off a deep or research stream.The returned text stops at 2,000 characters at every depth, with no sign when it was cut off. The chunk text in metadata.evidenceBundle of answer.done is never shortened, so read the retrieved text there when you need all of it.
Each query is answered on its own, even when you send an earlier response’s x-session-id as sessionId, so put everything a follow-up needs into its query.

Investigate an Answer

When an answer looks wrong, pass its query record ID to Get Query Record to read the run’s recorded steps. Use the same ID to inspect the evidence: When the right chunks weren’t retrieved or ranked low, tune retrieval in Dify. If you didn’t keep the ID, look for the run in List Query Records.

Prevent Duplicate and Stale Writes

Send an Idempotency-Key header with every write that takes one. If the response is lost, send the same request with the same key: you get the original task, run, or job back instead of a second one. Use a new key for each new operation, since a repeated key returns the earlier result, even one that has finished. Read an object’s current version right before you update or delete it, and send it in the operation’s version field. A 409 then means it changed after you read it: read it again, check that your change still applies, and resend. A 409 can also mean the Idempotency-Key was already used for a different request: use a new key.

Run a Research Task

Unlike a query at research depth, which answers within the stream, a research task runs in the background and keeps its results. Use a query when a user is waiting for the answer, and a research task when the work can wait or you’ll need the results later.
1

Plan

Send your question as query to Plan Research Task, with the mode and topK you want to use. It returns the estimated cost, latency, and steps without starting anything.
2

Create

Call Create Research Task with the same question and settings. To reject the task up front when its estimates go beyond what you’ll accept, add limits: a task whose estimates exceed them fails with 422.To cap spending while the task runs, add budgetUsd. When you need an answer, set it well above the plan’s estimates.costUsd.max, because each model call has to fit in the budget at the most it could cost. A task that reaches its budget ends as canceled.
3

Poll

Call Get Research Task with the returned task ID until the task ends.
4

Read the results

Call List Research Task Results and check the last result for answer.

Browse Documents and Chunks

A document is the item the Document tab shows. It has a document ID, and the file stored behind it has a separate document file ID. A content update, including one from a source sync, stores a new file with a new ID, but the document keeps its ID. Store the document ID, and follow its revisions for the content history. To show which document a citation came from, pass its documentAssetId to Get Document by File with 1 as document_asset_version. To read a document’s chunks, pass the document ID and a revision number to List Chunks. For the content in use for retrieval, take active.revision from Get Document. For older content, find the revision in List Document Revisions. To set a document’s metadata from another system, such as a CMS or a ticketing tool, call Update Document Metadata.

Add a Source

A source reads through a connection: the provider account or API key set up under Integrations > Data Source and linked to this knowledge base. Add the first source from each provider in Dify, on the knowledge base’s Source tab. To add more over the API:
  1. Call List Source Connections and pick an active connection whose configuration names the provider you want.
  2. Call Create Source with the connection’s id as connectionId and its configuration.providerKind as metadata.providerKind. Set type and uri by what the source reads:
    • A website: type: web, with the site’s root URL as uri.
    • An online document platform or drive: type: connector, with connector://<connectionId> as uri.
    Create Source takes no Idempotency-Key, and sending it twice creates two sources. Include a unique metadata.client_request_id: if the response is lost, look for it in List Sources before you create the source again.

Import Website Pages

Fill a website source in one of three ways:
  • Pick pages from a crawl preview.
  • Import URLs you already know.
  • Sync a source that has no page list yet: Dify crawls the whole site and imports every page it finds.
Each import replaces the source’s page list, so send every page you want to keep, not only new ones. Later syncs refresh the pages on the list. To pick pages from a crawl preview:
1

Preview the crawl

Call Preview Website Crawl, then poll Get Source Run with the returned id until state is preview_ready or the run ends.A run that ends zero_results found no pages. Check the source’s URL and crawl settings, then preview again.
2

Pick pages

Page through List Crawl Preview Pages with the run ID, and collect the page_id of each page to import.
3

Import

Call Import Selected Pages on the same run with those pageIds. The run continues under the same ID: follow it until it ends.
To import pages whose URLs you already know, call Import Website Pages with them as sourceUrls. Pages you leave out lose their documents at the next sync. To delete them in the same run instead, also set replaceExistingSelection: true.

Import Online Documents and Drive Files

Over the API, you can fill a new connector source once. After a source has imported items, in Dify or over the API, an import can only drop items: one that names a new item fails, even though its failure suggests a retry. Add new items in Dify. The items you send become the source’s whole content: documents for items you leave out are removed in the same run.
  1. Browse with List Source Pages for an online document source, or List Source Files for an online drive, as the source’s metadata.providerKind says.
  2. Call Import Source Items with the kind that matches the provider and items built from what you browsed, following the operation’s providerItemId format exactly.
  3. Follow the run with the returned id.

Follow Source Runs

Follow a run with Get Source Run, using the id from the response that started it, until it ends. A run that reaches completed has already indexed and activated every item it imported or refreshed, so there’s no indexing to track separately. A source handles one run at a time: starting another sync or import while one is active fails with 502. Wait for the active run to end, or cancel it with Cancel Source Run. A crawl preview counts as active until you import from it or cancel it, so cancel a preview you won’t import from. To find a run you didn’t start, such as a scheduled sync or one started in Dify, call List Source Runs. When a run fails, read its failure to see why. To rule out bad credentials, call Test Source Credentials: if valid is false, correct the connection’s credentials in Dify. To run a failed or canceled run again from the start, under the same ID, call Retry Source Run. To repeat a canceled crawl preview or a failed Import Website Pages run, start a new preview or import with a new Idempotency-Key instead.

Sync and Schedule Sources

To fetch a source’s latest content now, call Sync Source, then follow the run it returns. To sync on a schedule, save one for each source:
1

Read both versions

Read the source’s version from Get Source, then the schedule’s revision from Get Sync Policy. For a source with no schedule yet, Get Sync Policy returns 404: use 0 as the revision.
2

Save the schedule

Call Update Sync Policy with revision as expectedRevision and version as expectedSourceVersion.
The first scheduled sync runs one interval after you save, so sync now as well if you want fresh content right away. After each import into a scheduled source finishes, read both values again and save the schedule. An import changes the source’s version, and a schedule still bound to the old one turns itself off at its next due time. To stop scheduled syncs, save mode: manual with enabled: false. Setting the source’s status to disabled with Update Source only pauses them, and a sync that came due in the meantime runs as soon as the source is active again.

Re-index and Track Indexing

When indexing fails or is canceled, restart the task with Retry Indexing Task. When a document indexed but came out wrong, re-index it. A model change needs no re-index: it rebuilds what it affects on its own. Call Re-index Documents with documentIds or with all: true. Only queued items started a task: keep compilation_job.id from each of them. To know when new content is in use, poll the indexing task until it ends:

Change Models or Retrieval Settings

Choose models from Get Available Models. It needs a key with access to all knowledge bases: a key scoped to specific ones gets 403 forbidden. If you set models before the first document is indexed, they aren’t validated until that document is indexed. Then check issues in Get Knowledge Base Settings: it lists whatever keeps the knowledge base from being ready. While a document is being indexed, a model change is rejected with 409: wait for indexing to finish, or cancel its tasks, first. Once the knowledge base has indexed content, most settings changes run as a migration in the background:
1

Update

Call Update Knowledge Base Settings. A 202 means the change started a migration: keep migration.id.
2

Poll

Call Get Settings Migration with migration.id until the migration ends.
Each update can change either the embedding model or the retrieval settings, not both: a call with both is rejected with 422. To change both, send the embedding change, wait for its migration to succeed, then send the retrieval change.

Delete Documents and Sources

To remove a whole document, delete it in Dify. Over the API, you can delete document files (Delete Document File, Delete Document Files in Batch) and sources (Delete Source). Deleting a document file deletes only the revision built on it, not the document. Avoid deleting the active revision’s file. No older revision takes its place, and the document drops out of List Documents and Dify’s document list. It isn’t deleted, though, and still counts toward your document quota. Deleting a source also deletes the documents it imported. To keep them, first save the IDs of files with that source_id from List Document Files, because their source_id becomes null once the deletion completes. Then delete the source with documents=keep. The kept documents are hidden until the deletion completes, and after that no source updates them. To confirm a deletion finished, poll Get Deletion Job with job.id until the job ends. For a batch, poll Get Deletion Batch with batch_id until every entry in results is rejected or its job has ended. A rejected file wasn’t deleted, and error says why. A pending entry means the batch stopped partway, and polling won’t move it: send the same request again with the same Idempotency-Key to retry only the pending files. A deletion that ends failed can’t be retried or cleared, over the API or in Dify. What it was deleting stays hidden, including the documents of a source deleted with documents=keep.

Handle Errors

Errors carry the same code, message, and status described in Errors, and many add a failure object: its retryPolicy says whether a retry can help. Run Query errors have their own shape, listed on its page. On a 502, retry a read after a pause. A write may have taken effect before its response was lost. Resend it with the same Idempotency-Key, or, for a write that takes no key, check its outcome before sending it again. A 502 when starting a sync or import can also mean the source already has an active run: see Follow Source Runs. Except on Get Available Models, 403 forbidden means the workspace has reached its knowledge base request rate limit. The whole workspace shares the limit, and every call counts, reads included. A call the limit rejects counts too, so back off before retrying, and space out your polling. To poll many indexing or bulk tasks in one call, pass their IDs to List Background Tasks as task_ids.

Request Size Limits

Keep each request below the byte budget on its operation page, with some room to spare. Dify measures the request after adding defaults and its own fields, so it can go over even when every field is within its character limit.
Last modified on October 28, 2026