Skip to main content

Data sources API

Data sources are the content your chatbot answers from. These endpoints are nested under a chatbot and require session authentication.

Base path:

/chatbots/:chatbotId/datasources

Add a source

POST /chatbots/:chatbotId/datasources

The type field selects what the other fields mean.

Website

{
"type": "url",
"sourceUrl": "https://example.com",
"isRecursive": true
}

isRecursive: true follows internal links and indexes the site. false indexes only the URL you gave.

Pasted text

{
"type": "text",
"title": "Returns policy",
"content": "You can return any unused item within 30 days..."
}

title is how you will identify this source later — make it descriptive.

YouTube

{
"type": "youtube",
"sourceUrl": "https://www.youtube.com/watch?v=..."
}

The video must have captions available. Without them there is no transcript to index and the source errors.

Returns the created data source. Indexing runs in the background — poll the chatbot's status to know when it is done.

Rate-limited as an ingestion operation.


Upload a document

POST /chatbots/:chatbotId/datasources/file

multipart/form-data, with the file in a field named file.

curl -b cookies.txt -X POST \
https://apimesh.byteleaps.tech/api/chatbots/CHATBOT_ID/datasources/file \
-F 'file=@price-list.pdf'

Accepted formats

ExtensionType
.pdfapplication/pdf
.docapplication/msword
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.pptapplication/vnd.ms-powerpoint
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.csvtext/csv, application/csv
.txttext/plain

Both the extension and the content type must be acceptable. A .pdf sent with the wrong content type is rejected.

Maximum size: 25 MB.

Errors

StatusMessage
400File too large. Max limit is 25MB.
400Unsupported file type: <type>

Both are client errors with a clear message — they are not server failures, and retrying without changing the file will not help.


List sources

GET /chatbots/:chatbotId/datasources

Returns every source with its current state:

FieldMeaning
typeurl, file, text, youtube
statuspending, processing, done, error
pageCountDocuments read
chunkCountSearchable pieces produced
errorMessageWhy it failed, when status is error
siteTypestatic, spa, nextjs, nuxt, unknown
sitemapUrlThe sitemap used, if one was found
sparseContenttrue when very little usable text was extracted
crawlSummaryAttempted, succeeded, failed and skipped counts, plus the skipped URLs

crawlSummary and sparseContent are the two fields worth surfacing in any tooling you build — they explain nearly every "why isn't my chatbot answering this?" question.

Reading the crawl summary


Refresh a source

POST /chatbots/:chatbotId/datasources/:id/refresh

Re-reads one source and replaces its indexed content. Other sources are untouched.

Only meaningful for sources with a live original — websites and YouTube videos. Pasted text and uploaded files have nothing external to re-read.

Rate-limited as an ingestion operation.


Delete a source

DELETE /chatbots/:chatbotId/datasources/:id

Removes the source and its indexed content. The chatbot stops being able to answer from it immediately.

This is the correct way to retire content — a discontinued product, an expired promotion, a withdrawn policy. Refreshing alone does not always remove content you deleted from the source site.


Chatbot logos are a different endpoint with different rules.

POST /uploads/:chatbotId/image

multipart/form-data, field name file.

AcceptedPNG, JPEG, WebP
Maximum size2 MB
RejectedSVG, and everything else
{
"success": true,
"data": { "url": "/uploads/1737465600000-a1b2c3....png" }
}

The returned url is root-relative. Set it on the chatbot with PATCH /chatbots/:id as avatarUrl; the widget resolves it against the API origin.

SVG is rejected deliberately

SVG files can contain executable scripts, and uploaded images are served from the API's own origin. Accepting them would create a stored cross-site-scripting vector. Export as PNG.