Skip to content

Manage the knowledge base

The assistant answers callers from the business’s knowledge base: text notes, uploaded files and imported websites, the same documents the owner sees under Documenti in Talki. /v1/documents reads them under knowledge:read and writes them under knowledge:write, an opt-in scope. Neither scope includes the other, so an integration that writes documents and then follows their status needs both; see Scopes.

Whatever a document says, the assistant tells every caller who asks. The owner can edit or delete what you write, and nothing asks for their approval first: agree with the business what you add.

Task Request
List documents, of every location or one GET /v1/documents
Read one, with its status GET /v1/documents/{document_id}
Read the text the assistant searches GET /v1/documents/{document_id}/text
Download an uploaded file GET /v1/documents/{document_id}/file
List a website’s pages GET /v1/documents/{document_id}/pages
Add a note, a file or a website POST /v1/documents
Find a site’s pages before importing it POST /v1/documents/discover
Replace a note or a file, import a website again PUT /v1/documents/{document_id}
Rename a document, switch it off or on PATCH /v1/documents/{document_id}
Delete a document DELETE /v1/documents/{document_id}
Drop one page of a website DELETE /v1/documents/{document_id}/pages/{page_id}
  • Text note: content you already hold as text, such as an answer, a price list or a policy. The assistant reads exactly what you send, title included, and you replace it in place. For a FAQ you manage, one short note per question lets you replace, switch off or delete each entry on its own.
  • File: a PDF, DOCX, XLSX, TXT or CSV the business already has. Its text is read after the upload, and the file is kept for download when file_available says so.
  • Website: pages of the business’s site. Their text is read from the pages you choose; import the site again when it changes.
Terminal window
curl --fail-with-body -X POST https://api.talki.it/v1/documents \
-H "Authorization: Bearer $TALKI_API_KEY" \
-H "Idempotency-Key: note-bridal-sundays" \
-H "Content-Type: application/json" \
--data '{"title":"Bridal hair","body":"Bridal hair is booked on the first Sunday of each month, by appointment only."}'

The answer is 202, with the document still processing:

{
"id": "3f6b1c9e-8d27-4a5f-b0e4-6c2d9a7f1e83",
"location_id": "0b7d4e19-8a2c-4f61-9d3e-5c1a7b2f8e40",
"title": "Bridal hair",
"source": "text",
"mime_type": "text/markdown",
"size_bytes": 77,
"chunk_count": 0,
"file_available": false,
"status": "processing",
"status_error": null,
"enabled": true,
"faq": false,
"copy_group_id": null,
"created_at": "2026-11-02T09:30:12Z",
"updated_at": "2026-11-02T09:30:12Z"
}
  • Idempotency-Key is required on POST /v1/documents. A create retried without it would add a second document, which the assistant reads beside the first.
  • ?location_id= names the location whose assistant uses the document; without it, the main location’s. location_ids in the body adds a copy at each other location named; see Copies at other locations.
Terminal window
curl --fail-with-body -X POST https://api.talki.it/v1/documents \
-H "Authorization: Bearer $TALKI_API_KEY" \
-H "Idempotency-Key: upload-price-list-2026-11" \
-F "file=@price-list.pdf;type=application/pdf"
  • Send the file as multipart/form-data, in a field named file. Its name becomes the document’s title. location_ids goes as one form field per location.
  • A part sent with no type, or as application/octet-stream, is typed by its file extension. Any other type that is not one of the accepted ones, or content that does not match its type, is refused with 415 unsupported_file_type.
  • The 202 carries the document, and its copies exist from then too, before the file is read.
  • Reading can still fail after the 202: a file with no readable text, an encrypted DOCX or XLSX, or a file over one of the reading limits in Limits. The document then turns failed, with status_error.
  1. POST /v1/documents/discover looks for the pages of the site at url, from its sitemap or its links, and returns them with the plan’s max_pages. It imports nothing.

    Terminal window
    curl --fail-with-body -X POST https://api.talki.it/v1/documents/discover \
    -H "Authorization: Bearer $TALKI_API_KEY" \
    -H "Content-Type: application/json" \
    --data '{"url":"https://salone-esempio.it"}'
  2. POST /v1/documents with source: "website", the url and the pages you chose. Without pages, only the page at url is read.

    Terminal window
    curl --fail-with-body -X POST https://api.talki.it/v1/documents \
    -H "Authorization: Bearer $TALKI_API_KEY" \
    -H "Idempotency-Key: site-salone-esempio" \
    -H "Content-Type: application/json" \
    --data '{"source":"website","url":"https://salone-esempio.it","pages":["https://salone-esempio.it","https://salone-esempio.it/prezzi"]}'
  3. Once the document is ready or failed, GET /v1/documents/{document_id}/pages lists each page with its status, which says whether the page was read and is searched; see List a website’s pages.

  4. DELETE /v1/documents/{document_id}/pages/{page_id} drops a page and what it said; the assistant stops using it once the document is ready again. Dropping the last page that was read deletes the document, with document.deleted.

  • A site already imported at a location is refused there with 409 conflict, and the message names its document: import that one again with PUT.
  • An address that is not a public http or https address is refused with 400 invalid_parameter, as is a pages list longer than the plan allows.
  • Discovery that cannot read the site answers 502 api_error: check the address, or retry later.
  • While the site is being imported, PUT and page deletes are refused with 409 document_not_ready: retry once the document is ready or failed.
  • A page delete that would leave the site with no text to search, while other pages are still listed as read, is refused with 409 conflict. A retry gets the same answer: import the site again with the pages to keep, or delete the document.
  • Page requests on a document that is not a website, listing or deleting, are refused with 400 invalid_parameter.
  • A website’s title is its address, and cannot be renamed.

The assistant uses a document only once it is ready. Every write that changes what a document holds answers before indexing, with the document processing; that includes a note’s new title.

  • Each change of status sends a document.updated. Without webhooks, poll GET /v1/documents/{document_id}.
  • failed comes with status_error, a sentence for people: show it, and do not branch on its text. Send the content again with PUT: a new POST adds a second document, or for a website answers 409 conflict.
  • A document that already had content keeps answering with it while it is processing again, and after a failed.
  • A document still processing six hours after its last change turns failed.
  • A file upload or a website import that failed before holding anything is deleted seven days after it failed, with document.deleted.
  • GET /v1/documents/{document_id}/text returns a note’s text as last written, before it is indexed. For a file or a website it is empty until the document is first ready.

PUT /v1/documents/{document_id} keeps the document’s id:

  • A note takes JSON with its new body, and title to rename it in the same request. It can be replaced at any time.
  • A file takes multipart/form-data with the new file, under the same rules as an upload. The document’s title and size_bytes become the new file’s once it is ready.
  • A website takes JSON with the pages to read, or {} to read again the pages it holds. A site whose import failed before any page was read holds none, and {} reads only its address: send pages again.

The document turns processing, and keeps answering with its previous content until the new one is ready.

  • A note is never refused for its status.
  • A file can be replaced again while its new version is still being read: the newer file takes its place. Until the last file sent is in place, a replacement is refused with 409 document_not_ready: while the file’s first upload is still processing, and for a moment while a new version that has been read replaces the previous one. Retry shortly.
  • A website is refused with 409 document_not_ready while it is being imported: retry once it is ready or failed. For a moment while a new version switches in, a ready site is refused the same way: retry shortly. It is refused with 409 conflict when an older document holds the same site at its location: import that one again, or delete one of the two.
  • With ?also=copies, the document_not_ready refusals apply to each copy too, and the message names the copy that holds the request up: retry, or send it without ?also=copies.
  • A body of the wrong kind for the document, or a JSON field the body does not take, is refused with 400 invalid_parameter; for a field, the message names it. PUT takes no source, so a JSON create body sent again with PUT is refused.

PATCH /v1/documents/{document_id} takes title, enabled or both. An omitted field is left as it is, and null is refused.

  • enabled: false keeps the document, but the assistant stops using it until enabled: true.
  • A note’s new title is indexed again, as its text is.
  • A file’s title cannot change while its file is processing, nor, with ?also=copies, while a copy’s file is: the request is refused with 409 document_not_ready. Rename it once the file is ready or failed, or without ?also=copies. A note is never refused.
  • A PATCH that changes nothing sends no document.updated.

A document belongs to one location. On an account with several, location_ids on POST /v1/documents makes a copy at each location named: a document of its own, with its own id, sharing copy_group_id. GET /v1/documents?copy_group_id= lists a group.

  • ?also=copies on PUT, PATCH, DELETE and a page delete applies the change to every copy too. Without it, only the document named changes, and its copies keep what they hold.
  • Each copy counts against the knowledge storage on its own.
  • 409 request_conflict means another request changed the copies at the same moment: retry.

GET /v1/documents/{document_id}/file returns an uploaded file as it was received, with its type in Content-Type and its name in Content-Disposition, when the document’s file_available is true.

  • file_available turns true shortly after a file is first ready, and later for a copy at another location. While it is false the download answers 404 resource_not_found.
  • A note, a website, a file whose first upload failed and a file whose upload was not kept have none to return. For a note, a website or a file that was read, GET /v1/documents/{document_id}/text returns its text instead.
  • A file being replaced returns its previous version until the new one has been read. It then has none until shortly after the new version is ready, and returns the new version from then.
  • 503 api_error means the file cannot be read right now: retry later.

The answers taught with POST /v1/unresolved_requests/{request_id}/teach go to the location’s FAQ note, the document with faq: true; a location has one at most. It is a text note like any other: PUT replaces its text, PATCH switches it off, and after a DELETE the next answer taught there starts a new one. The business edits it in Talki too, so read its text before you replace it.

What Limit
Note Text up to 100 KB in UTF-8; title up to 200 characters
File PDF, DOCX, XLSX, TXT or CSV, up to 10 MB or the plan’s lower limit
What is read from a file Up to 4 MB of text, 150 PDF pages, and 50,000 rows and 100 columns per spreadsheet, or the plan’s lower limits for pages and rows; a file over them, or an encrypted DOCX or XLSX, turns failed
Website import Up to the plan’s pages per import, max_pages from discovery
Addresses Public http or https, up to 2,048 characters
Knowledge storage The plan’s, across every document of the account, each copy counted on its own
Sandbox and test accounts 5 MB in all, 1 MB per file, 5 pages per import, 20 pages per PDF, or the plan’s lower limits
Rate POST, PUT, PATCH and discovery share 60 document writes a minute, on top of the write limit; see Rate limits

A write over the knowledge storage is refused with 413 payload_too_large; a website import over it turns failed instead, with status_error.

HTTP Code When
400 idempotency_key_required POST /v1/documents without Idempotency-Key
400 invalid_parameter An empty title or body, a title over 200 characters, pages over the plan’s limit, an address that is not public http or https, a body of the wrong kind for the document, a JSON field the body does not take (the message names it), a website’s new title, listing or deleting pages of a document that is not a website, or null in a PATCH
404 resource_not_found An unknown document, page or location, or a document with no file to download
409 conflict The website is already imported at that location, or an older document holds it there (the message names that document); or a page delete would leave the site with no text to search. Not retryable as sent
409 document_not_ready A file replacement before the last file sent is in place (retry shortly), a file’s rename while its file or a copy’s file is processing, a website re-import or page delete during an import, or a website re-import while a new version switches in (retry shortly). With also=copies, the message names the copy. Never for a note
409 request_conflict Another request changed the document’s copies at the same moment
413 payload_too_large A file over the upload size, a note over 100 KB, or the knowledge storage full for the plan
415 unsupported_file_type A file of a type not accepted or not matching its content, source: "file" in JSON, or a body neither application/json nor multipart/form-data
502 api_error Discovery could not read the site
503 api_error The file, or the text of a file or website, cannot be read right now, including to drop a page
Event When data.object
document.created A document is added: a note, an upload or a website, by a person, an app or an answer taught; one event per document, each copy included Document
document.updated Its title, content or enabled changes, it turns processing again, or its indexing ends ready or failed Document
document.deleted It is deleted, by a person or an app, with its last page that was read, or as a failed upload or import that held nothing Document, as it was
  • The events need knowledge:read. Receive them as a webhook or as app events.
  • They report every change, whoever made it: the owner in Talki, an app, an answer taught, or the indexing, whose ready or failed has origin.source system. A location added in Talki can bring copies of another location’s documents, each with its own document.created.
  • Your own writes come back too, with origin.source api and your credential’s ID in origin.credential_id. A response carries only the document named: apply the events for the copies a write makes with location_ids or changes with ?also=copies, or list them with ?copy_group_id=, rather than dropping your own.
  • Switching a document on or off, and some status changes, leave its updated_at as it is (see Retrieve a document), so order its events by the envelope’s created_at and skip an older one, or read the document again on each event.
  • GET /v1/documents is a newest-first list, not a change feed. To rebuild a copy, or to find deletions whose event you missed, walk it in full and drop the ids it no longer returns.