B BrandLeaf docs

Build your agent

Curated answers & CTAs

Curated answers and CTAs are the two kinds of "deterministic" behavior the widget supports — they bypass the LLM in favor of exact text or structured calls-to-action. Use them where you can't tolerate the model paraphrasing or going off-script.

When to use curated answers

Curated answers are for questions where the response has to be exact:

  • Pricing — visitors want numbers, not "around $99/month".
  • Legal / compliance — return policy, GDPR statement, contract terms.
  • Routing — "how do I contact you?" where you want to push a specific URL.
  • Brand-critical FAQs — your highest-stakes 5-10 questions.

Authoring

From /app/agents/{id}/curated:

  1. Question pattern (question_pattern column) — one or more trigger keywords. Use commas to split a single field into independent OR-tokens (pricing, refund, web design). The matcher splits on commas, lowercases each token, and short-circuits the LLM if ANY token appears as a substring of the visitor's message. Case-insensitive. Add variants (price, pricing, how much) so misspellings still hit.
  2. Answer — the exact text to stream back. Markdown is supported (bold, links, lists). Anchor markdown links inside the answer if you want clickable citations — there is no dedicated citation_url column.
  3. Priority — higher wins when multiple curated entries match the same input.
  4. Slug + KB title + KB published — toggle the row into a public Knowledge Base article. When kb_published = true the answer renders at /kb/{workspace.slug}/{slug} and the bot can recommend it mid-chat via the send_kb_article tool. The public knowledge base that lists every published answer, /kb/{workspace.slug}, is linked (copy + open) at the top of the Curated answers and Knowledge pages, as well as in Workspace settings.
  5. Knowledge base category (kb_category_id) — the section of the public knowledge base the article belongs to. Optional; see Public knowledge base below.
  6. Lang — optional ISO code so a single agent can serve curated answers per language.
  7. Enabled — boolean toggle. Lets you author then publish, or pause a curated row without deleting it.
  8. Conditions (conditions JSON) — optional matching constraints (e.g. page_url_prefix, visitor_lang) layered on top of the question pattern.

Public knowledge base

Every answer with Publish to /kb on becomes an article of the workspace's public help center at /kb/{workspace.slug}. Articles of every published agent in the workspace appear together. Answers that are disabled, not published to /kb, or on an unpublished or deleted agent never appear — not in lists, not in search, and their URLs return 404. A deleted workspace's knowledge base returns 404 on every page. The pages need no JavaScript, and the surrounding text (headings, search box, buttons) follows the visitor's language; articles show as written.

Categories

Categories group articles into sections. Manage them under Knowledge base categories at the bottom of the Curated answers page (/app/agents/{id}/curated):

  • Add — a name, an optional emoji as its icon, and an optional one-line description shown on the category card.
  • Edit (pencil) — rename it or change its icon and description.
  • Reorder — drag the handle. The order is the order of the cards on the knowledge-base home.
  • Delete (bin) — the category goes, its articles stay published and move to Other articles.
  • Assign — pick a category in the Knowledge base category field when you add an answer, or in the folder menu on any answer in the list. No category puts the article under Other articles.

Categories belong to the workspace, so the curated answers of every agent can use the same ones. The server refuses a category of another workspace. Managing categories takes the same role as managing curated answers (owner, admin or editor).

A category's page lives at /kb/{workspace.slug}/c/{category-slug}. The slug is made from the name when the category is created — "Billing and payments" becomes billing-and-payments, a second "Billing" becomes billing-2 — and stays the same when you rename the category, so links already shared keep working.

The knowledge-base home

/kb/{workspace.slug} opens with a search box, then one card per category in your order — icon, name, description and the number of published articles — then Other articles: the published articles without a category. A category shows once it has a published article. Without categories, the home lists every article under All articles, as before.

Category pages

/kb/{workspace.slug}/c/{category-slug} lists the category's published articles, highest priority first, each with the first line of its answer, under a breadcrumb back to the home. A category without published articles shows an empty state and asks search engines not to index it.

Article pages

Article URLs did not change: /kb/{workspace.slug}/{slug}, with or without a category (an article whose slug is c still opens there). Each article starts with a breadcrumb — Knowledge base › Category › Article — and, when it has a category, ends with up to five related articles from the same category.

Search

The search box opens /kb/{workspace.slug}?q=…. It lists published articles whose title, trigger question (question_pattern) or answer contains every word of the query, in any order and regardless of case; articles with the words in their title come first. Up to 50 results show, each with its category and an excerpt around the match, or a "no results" message. % and _ in a query match literally. Search pages are not indexed by search engines, and the whole knowledge base is rate-limited to 120 requests a minute per IP.

How matching works

Before the RAG pipeline runs, the message goes through CuratedAnswerMatcher. If any trigger matches, the curated text is returned and we never call retrieval or the LLM. That makes curated answers fast — usually under 100ms end-to-end — and cheap (no inference cost).

The streaming behavior matches the LLM's: tokens stream out one at a time over a small interval so the visitor sees the same typing animation. They have no way to tell a curated answer from a generated one.

CTAs

A CTA is a card the visitor can click — a button, a link, or both — rendered inline in the chat panel. Each CTA has:

FieldPurpose
titleOne-line headline.
descriptionOptional supporting text.
buttons1 or 2 buttons. Each has a label and an action (URL, send_message, lead_capture, dismiss).
conditionsWhen to show. Same shape as behavior-rule conditions.

Common CTA patterns

  • Pricing reveal — when visitor asks about cost, show a card with "Compare plans" / "Talk to sales" buttons.
  • Demo upsell — after 3 turns of product Q&A, show "Book a 15-min demo".
  • Exit intent rescue — when cursor leaves toward the address bar, show "Before you go — quick question?" with a one-click lead form.
  • Scroll-deep nudge — at 80% page scroll, offer "See it in action" → demo URL.

Editing

/app/agents/{id}/ctas is the management page. The form is a structured builder — you don't need to write JSON. Save creates or updates a behavior rule with kind=cta. Disable to keep the rule but stop showing it.

Testing CTAs and curated answers

The Playground (/app/agents/{id}/playground) is your sandbox. It runs the same pipeline as the live widget but with is_playground=true on the conversation, so it doesn't count against your monthly quota and stays out of the analytics report.

Type a trigger phrase and confirm the curated answer fires. Type something close-but-not-quite and confirm it doesn't (otherwise your triggers are too loose).