BrightshoalDocsOpen console
MenuGive an assistant knowledge

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).

text
add sources -> approve each revision -> build a publication -> wait until ready -> publish -> attach to assistants

Create 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" }'
Response 201
{ "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."
  }'
Response 201
{ "data": { "id": "ksrc_8b1c4e7a2d9f4a3b8c6e0d1f2a3b4c5d" } }
KindWhat to sendLimits
texttextUp to 200,000 characters.
urlurlA 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.
filefilename 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:

Terminal
curl https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d \
  -H "Authorization: Bearer $MLF_API_KEY"
Response
{
  "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:

Terminal
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:

Terminal
curl -X POST https://api.myleadsfactory.tech/api/knowledge/kb_5e2a9c1d7b3f4e8a9c0d1e2f3a4b5c6d/publications \
  -H "Authorization: Bearer $MLF_API_KEY"
Response 202
{ "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:

Terminal
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.

config.knowledge
{
  "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:

Terminal
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?" }'
Response
{
  "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:

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 base100
Characters per source200,000
File size5,000,000 bytes
PDF length100 pages
Characters per publication2,000,000
Knowledge bases per assistant50
Bases searched per question4, highest priority first

When the API says no

StatusCodeWhat to do
403organization_knowledge_access_requiredUse an org-wide key, including to change an assistant's knowledge.
403knowledge_owner_requiredA project key tried to create a base. Use an org-wide key.
400invalid_knowledge_payloadA field is missing, too long or unknown (including a text over 200,000 characters). Check the body against the tables above.
400source_text_required_or_too_largeA text source was empty.
400source_too_largeThe page or file yielded more than 200,000 characters.
400source_needs_review_no_textThe page or file yielded too little text to use.
400knowledge_base_not_foundAn assistant's knowledge names a base that does not exist. knowledge_base_id says which.
409source_limit_reachedThe base has 100 active sources. Delete some, or start another base.
409review_all_public_sources_firstApprove every public source's latest revision, then build.
409publication_not_readyWait until the publication is ready.
409sources_changed_rebuild_publicationBuild a new publication and publish that one.
409knowledge_voice_requires_pipeline_assistantThis assistant uses a realtime voice model, which cannot search knowledge on calls. Set "voice": false for that base.
409test_publication_staleAnother publication went live after you picked this one for testing. Test it again, or build a new one.
410knowledge_attachments_movedSet knowledge in the assistant's config instead.
503knowledge_storage_not_configuredSource storage is not set up on this deployment. Contact us.
503knowledge_not_configuredPublication builds are not set up on this deployment. Contact us.

All requests and responses are in the knowledge reference.

Stuck on give an assistant knowledge?