Make it yours
Give an assistant knowledge
Put your pages, documents and notes into a knowledge base, review and publish them, and attach the base to an assistant so it answers from what is true for your business.
A knowledge base holds the material an assistant answers from: web pages, files and plain text. Nothing reaches an assistant by accident. Each source is reviewed, the reviewed set is built into a publication, and live conversations search only the publication you publish. Test chats can search a newer one first (below).
add sources -> approve each revision -> build a publication -> wait until ready -> publish -> attach to assistantsCreate a knowledge base
curl -X POST https://api.myleadsfactory.tech/api/knowledge \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Travel", "description": "Policies, destinations and prices" }'{ "data": { "id": "kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d", "name": "Acme Travel", "description": "Policies, destinations and prices", "enabled": true, "version": 1 } }Add sources
Add each source with POST/api/knowledge/{id}/sources. Every source has a kind, a title (1 to 200 characters) and an audience:
public: may be published to assistants and quoted to visitors.private: kept in the base for your team, never published. This is the default, so set"audience": "public"on anything an assistant should use.
curl -X POST https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d/sources \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "text",
"title": "Refund policy",
"audience": "public",
"text": "Deposits are refundable up to 30 days before departure. After that, refunds depend on the fare rules of each flight."
}'{ "data": { "id": "ksrc_8b1c4e7a2d9f4a3b8c6e0d1f2a3b4c5d" } }| Kind | What to send | Limits |
|---|---|---|
text | text | Up to 200,000 characters. |
url | url | A public https page on port 443, with no query string or # fragment. It is fetched once, now, and must allow it in robots.txt. Account, admin and search pages are refused. |
file | filename and the bytes as base64, in JSON (not a multipart upload) | .txt, .md, .html, .docx or .pdf (up to 100 pages), up to 5,000,000 bytes, with at least some readable text. |
A source can also carry expires_at (ISO 8601): after it, the source drops out of answers on its own.
To find the pages of a website, call POST/api/knowledge/{id}/discover with { "url": "https://www.acmetravel.com" }. It reads the site's sitemap.xml and returns up to 100 page URLs on the same site, without adding them. Add the ones you want as url sources.
To update a source, send it again with its id: a web page is fetched again, a file or text replaced. Its kind, audience and url cannot change (409 source_identity_is_immutable); add a new source instead. To take one out of answers at once, delete it with DELETE/api/knowledge/{id}/sources/{sourceId}.
Review and approve
Every time a source's content changes, it gets a new revision, and a revision must be approved before it can be published. Read the base to find them:
curl https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d \
-H "Authorization: Bearer $MLF_API_KEY"{
"data": {
"id": "kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d",
"sources": [
{
"id": "ksrc_8b1c4e7a2d9f4a3b8c6e0d1f2a3b4c5d",
"title": "Refund policy",
"kind": "text",
"audience": "public",
"revision": { "id": "krev_1f3e5a7c9b2d4f6a8c0e1b3d5f7a9c2e", "approved": false, "characters": 118 }
}
],
"publications": [],
"attachments": [],
"pending": []
}
}Check what was extracted with GET/api/knowledge/{id}/revisions/{revisionId} (it returns the title, text and url), then approve it:
curl -X POST https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d/revisions/krev_1f3e5a7c9b2d4f6a8c0e1b3d5f7a9c2e/approve \
-H "Authorization: Bearer $MLF_API_KEY"Build a publication
A publication is an immutable snapshot of every public source's latest approved revision. Building one indexes it in the background, so the call answers 202 straight away:
curl -X POST https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d/publications \
-H "Authorization: Bearer $MLF_API_KEY"{ "data": { "id": "kpub_6a8c0e2b4d6f8a1c3e5b7d9f0a2c4e6b" } }If a build is already queued or indexing, you get that one's id instead of a second build. The build is refused while any public source's latest revision is unapproved (409 review_all_public_sources_first), when there is no public source at all (400 no_public_sources), or when the public sources add up to more than 2,000,000 characters (409 publication_limit_reached).
Wait until it is ready
Read the base until the publication's status moves from queued and indexing to ready. How long that takes depends on how much you published.
async function waitUntilReady(baseId, publicationId) {
for (;;) {
const res = await fetch(`https://api.myleadsfactory.tech/api/knowledge/${baseId}`, {
headers: { Authorization: `Bearer ${process.env.MLF_API_KEY}` },
})
const { data } = await res.json()
const pub = data.publications.find((p) => p.id === publicationId)
if (pub?.status === 'ready') return pub
// a provider indexing failure is retried automatically while `retrying` is true
if (pub?.status === 'failed' && !pub.retrying) throw new Error(`publication failed: ${pub.error}`)
await new Promise((r) => setTimeout(r, 5000))
}
}A failed publication carries an error. When indexing failed at the provider and no source has changed since, it is retried automatically (up to five attempts) and shows retrying: true. Once retrying is false, retry it yourself with POST/api/knowledge/{id}/publications/{publicationId}/retry.
Publish it
Make the ready publication the one assistants search:
curl -X POST https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d/publications/kpub_6a8c0e2b4d6f8a1c3e5b7d9f0a2c4e6b/publish \
-H "Authorization: Bearer $MLF_API_KEY"The switch is atomic: answers move from the old publication to the new one at once. If sources changed after you built it, publishing is refused with 409 sources_changed_rebuild_publication; build again. A publication you published before can be published again, which is how you roll back.
Attach it to an assistant
An assistant answers from the knowledge bases named in its config, under knowledge. Each base id maps to where it is used, chat (website and WhatsApp) and voice (calls), and a priority from 0 to 100. All three fields are required. Each search reaches up to four of the assistant's bases that have a live publication, highest priority first, so priority decides which bases are used when it has more than four.
{
"kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d": { "chat": true, "voice": true, "priority": 0 }
}PATCH/api/assistants/{id} replaces the whole config, so read the assistant, add knowledge and send the config back. The change is live at once. Later writes that leave knowledge out keep it.
curl -s https://api.myleadsfactory.tech/api/assistants/asst_7d2e9b14c6a04f3e8b5d1a9c0e7f6b23 \
-H "Authorization: Bearer $MLF_API_KEY" \
| jq '{ config: (.data.config | .knowledge += { "kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d": { chat: true, voice: true, priority: 0 } }) }' \
| curl -X PATCH https://api.myleadsfactory.tech/api/assistants/asst_7d2e9b14c6a04f3e8b5d1a9c0e7f6b23 \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d @-To change the channels, send the entry again. To detach, set both chat and voice to false, or send knowledge without the base ({} detaches every base). GET/api/knowledge/{id} lists the assistants answering from the base in attachments.
Check what it will find
POST/api/knowledge/{id}/search searches the published publication the way an assistant does, so you can see which passages a question finds before a visitor asks it:
curl -X POST https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d/search \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "query": "Can I get my deposit back?" }'{
"data": {
"status": "ok",
"evidence": [
{
"knowledge_base_id": "kb_5e2a...",
"publication_id": "kpub_6a8c...",
"source_id": "ksrc_8b1c...",
"revision_id": "krev_1f3e...",
"title": "Refund policy",
"url": null,
"text": "Deposits are refundable up to 30 days before departure...",
"score": 0.82
}
],
"elapsed_ms": 412
}
}status is ok with passages, empty when nothing matched or nothing is published, and unavailable when search could not run in time. The query is up to 2,000 characters.
Try changes before they go live
Test chats (on a test publishable key, or the console's test chat) let you try knowledge before visitors see it:
- A new publication: POST
/api/knowledge/{id}/publications/{publicationId}/testmakes test chats search areadypublication while live chats keep the published one. Search it yourself with"publication": "test"in the search body. When it answers well, POST/api/knowledge/{id}/test-publication/promotepublishes exactly that publication; DELETE/api/knowledge/{id}/test-publicationdrops it instead. - A new attachment: put the
knowledgechange in the assistant's draft with PUT/api/assistants/{id}/draftinstead of patching live. Test chats run the draft, and POST/api/assistants/{id}/publishmakes it live. Until then, the base'spendinglist shows what publishing would attach, update or detach.
Promoting is refused with 409 test_publication_stale when another publication went live after you picked the test one, since it may lack what that one added. Send expected_publication_id to be sure you promote the publication you tested.
Limits
| Limit | |
|---|---|
| Active sources per base | 100 |
| Characters per source | 200,000 |
| File size | 5,000,000 bytes |
| PDF length | 100 pages |
| Characters per publication | 2,000,000 |
| Knowledge bases per assistant | 50 |
| Bases searched per question | 4, highest priority first |
When the API says no
| Status | Code | What to do |
|---|---|---|
| 403 | organization_knowledge_access_required | Use an org-wide key, including to change an assistant's knowledge. |
| 403 | knowledge_owner_required | A project key tried to create a base. Use an org-wide key. |
| 400 | invalid_knowledge_payload | A field is missing, too long or unknown (including a text over 200,000 characters). Check the body against the tables above. |
| 400 | source_text_required_or_too_large | A text source was empty. |
| 400 | source_too_large | The page or file yielded more than 200,000 characters. |
| 400 | source_needs_review_no_text | The page or file yielded too little text to use. |
| 400 | knowledge_base_not_found | An assistant's knowledge names a base that does not exist. knowledge_base_id says which. |
| 409 | source_limit_reached | The base has 100 active sources. Delete some, or start another base. |
| 409 | review_all_public_sources_first | Approve every public source's latest revision, then build. |
| 409 | publication_not_ready | Wait until the publication is ready. |
| 409 | sources_changed_rebuild_publication | Build a new publication and publish that one. |
| 409 | knowledge_voice_requires_pipeline_assistant | This assistant uses a realtime voice model, which cannot search knowledge on calls. Set "voice": false for that base. |
| 409 | test_publication_stale | Another publication went live after you picked this one for testing. Test it again, or build a new one. |
| 410 | knowledge_attachments_moved | Set knowledge in the assistant's config instead. |
| 503 | knowledge_storage_not_configured | Source storage is not set up on this deployment. Contact us. |
| 503 | knowledge_not_configured | Publication builds are not set up on this deployment. Contact us. |
All requests and responses are in the knowledge reference.