{"generatedAt":"2026-06-26T05:20:35.464Z","count":34,"articles":[{"slug":"live-chat-inbox-ticketing-improvements","title":"Live chat & inbox: merge chats, draggable widget, new-chat popups, and more","summary":"Eight fixes and upgrades to the live chat widget, inbox, and ticketing — sticky reply box, a movable widget, on-screen new-chat alerts, conversation merging, the page a chat came from, an agency link, a Tickets tab for support agents, and viewer-aware routing.","body":"This release works through a batch of real feedback from teams running\nlive chat day to day. Eight changes across the widget, the inbox, and\nticketing.\n\n## Live chat widget\n\n- **Move the widget anywhere.** Visitors can now drag the floating chat\n  button (and its panel) out of the way — handy when it covers a \"Buy\"\n  button, a form field, or a cookie banner. Where they drop it is\n  remembered on that device, so it stays put on the next page.\n- **We capture which page a chat started on.** Every conversation now\n  records the visitor's actual page URL + title at the moment they opened\n  the chat (previously this quietly logged an internal URL). You'll see it\n  in the inbox as **\"Came from ↗\"** — one click opens that page. Especially\n  useful when you run chat across many whitelabel sites and need to know\n  instantly which client a chat belongs to.\n\n## Inbox\n\n- **The reply box stays put.** The composer is now pinned to the bottom of\n  the conversation — no more scrolling down through a long thread to find\n  where to type.\n- **On-screen alert for new chats.** In addition to the notification\n  sound, a popup now appears (bottom-right) the moment a new chat comes in,\n  even when you're on another page — with the visitor's name, the first\n  message, and a one-click **Open chat**. Easy to miss the chime; hard to\n  miss the card.\n- **Merge conversations.** When a customer goes quiet and comes back later\n  in a fresh chat with the same issue, you can now fold the two threads\n  into one. Open the live chat, click **⤵ Merge**, and pick the earlier\n  conversation — its messages move across in chronological order and the\n  old thread is closed and linked to the survivor.\n- **Quick agency link.** Each widget now has a **Whitelabel / agency URL**\n  field (Widgets → your widget → Routing). Set it to the client's site or\n  dashboard and it shows up in the inbox conversation panel as a one-click\n  shortcut — a fast way to jump to the right brand when you support many.\n\n## Ticketing & roles\n\n- **Tickets tab for support agents.** Support-agent teammates (the\n  inbox-only role) now see a **Tickets** tab alongside their Inbox, instead\n  of only the inbox, wherever ticketing is enabled.\n- **Routing skips viewers.** Viewers are read-only and can't reply, so\n  they no longer appear in a widget's \"Eligible teammates\" picker and are\n  never auto-routed a chat. The reply and merge actions are enforced\n  server-side too, so a read-only role can't accidentally take over a chat.\n\nNothing here changes how your existing widgets are installed — current\nembed snippets keep working as-is and pick up the new behaviour\nautomatically.","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/live-chat-inbox-ticketing-improvements","publishedAt":"2026-06-12T03:01:04.927Z","updatedAt":"2026-06-26T03:29:49.606Z"},{"slug":"native-crm-rolling-out","title":"Native CRM: skip the GoHighLevel setup and start with built-in contacts","summary":"Workspaces without a CRM can now run on a built-in contacts and outbound backend instead of being forced to connect GoHighLevel first. Foundation is live; dashboard UI lands next.","body":"Until now, building an agent meant connecting GoHighLevel before you\ncould do anything beyond a website widget. For teams who just want to load\na lead list and let an agent reach out, that was the friction point that\nmade people bounce.\n\n**Native CRM** is the built-in alternative. Your workspace gets its own\ncontacts, lists, conversations, and messaging — all backed by us, no\nexternal CRM required. Connect GoHighLevel later if you outgrow it; nothing\nmoves until you decide to.\n\n## What you get\n\n- **Contacts database** — name, email, phone, tags, custom fields. Every\n  contact is workspace-scoped and dedupes automatically by email + phone.\n- **Lists and segments** — static lists you build manually, or smart lists\n  that resolve at read time from a tag or name filter.\n- **CSV import** — upload a lead list, map columns, and the importer\n  handles dedupe, suppression, and per-row error tracking so you can fix\n  and re-upload just the rejected rows.\n- **Suppression list** — workspace-wide opt-out store. STOP replies and\n  bounces register here automatically; you can also block addresses\n  manually.\n- **Custom fields** — define your own fields and reference them in agent\n  merge tags ({{contact.<field_key>}}) the same way you would on GHL.\n\n## What's *not* on the native plan\n\nPipelines, deals, and calendar booking. If your agent needs to move\nopportunities through stages or book appointments, connect GoHighLevel or\nHubSpot — those are the upgrade path.\n\n## What's live today vs. coming next\n\nThe backend foundation is **live as of this release**: schema, the adapter\nthe agent runs on, the import pipeline, suppression, and the provisioning\nendpoint. If you're API-savvy you can already drive everything via direct\ncalls.\n\nThe dashboard UI for managing contacts, lists, and imports is **rolling\nout next sprint** — that's the missing piece for self-serve. Twilio/SMTP\noutbound delivery (turning a queued message into an actual SMS or email)\nis the sprint after that.\n\nWe'll bump this article when each piece lands. If you want early access\nto the API while the UI is still in flight, reach out.","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/native-crm-rolling-out","publishedAt":"2026-06-12T03:01:05.309Z","updatedAt":"2026-06-26T03:29:56.013Z"},{"slug":"click-to-call-widget","title":"Click-to-call buttons, inline embeds, and hosted call pages","summary":"Drop a styled \"Talk to us\" button on any landing page, share a hosted page link anywhere, or paste a button into your email signature.","body":"The **Widgets** menu (formerly \"Chat Widgets\") now hosts two widget\ntypes: the existing chat widget and a new click-to-call button. Both ride\nthe same install snippet, the same allowed-domains controls, and the same\nvoice-agent routing.\n\n## What you get\n\n- **Click-to-call button** — a styled button on your site that opens a\n  voice call with your agent. Floating bottom-right or inline in the page.\n- **Hosted call page** — a shareable URL (`yourdomain.com/c/your-brand`)\n  with a clean landing page. No website install required.\n- **Email signature snippet** — a one-line HTML pill that links to the\n  hosted page. Paste into Gmail, Outlook, or Superhuman.\n\n## Create one\n\n1. Go to **Widgets** → **+ New widget**\n2. Pick **Click-to-call button**\n3. Choose the voice agent under **Routing → Default agent**\n4. Style the button (label, shape, size, icon, text colour) under **Button styling**\n5. Set a slug under **Hosted call page** to enable the shareable URL + email signature\n\nClick-to-call widgets default to having voice on, so you don't need to\ntoggle anything else. The voice agent inherits its system prompt and\nvoice config from the agent you picked in step 3.\n\n## Embed modes\n\n**Floating** is the default — a pinned button in the corner of the host\npage (bottom-left or bottom-right).\n\n**Inline** lets you drop the button into a specific spot on the page.\nPlace a target div where you want the button to appear, then point the\nscript at it:\n\n```html\n<div id=\"voxility-call\"></div>\n<script src=\"https://yourdomain.com/widget.js\"\n        data-widget-id=\"wgt_xxx\"\n        data-public-key=\"widget_pub_xxx\"\n        data-mount=\"#voxility-call\"\n        async></script>\n```\n\nThe widget editor toggle (\"Floating button\" / \"Inline (in-page)\") flips\nthe snippet for you — copy and paste.\n\n## Hosted call page\n\nEnable it by setting a slug. The URL becomes `yourdomain.com/c/<slug>`.\nThis page:\n\n- Works without an embed — just share the link\n- Has its own SEO-indexable landing UI with optional headline + subtext\n- Bypasses the widget's allowed-domains check (it's hosted on our domain)\n- Pulls the same voice agent the widget points to\n\nGreat for: SMS replies (\"Tap here to call us\"), Linktree-style bios, QR\ncodes on print, customer-success follow-ups.\n\n## Email signature snippet\n\nOnce a slug is set, the editor exposes a copy-paste HTML snippet that\nrenders a styled call-now pill linking to the hosted page. Drop it into\nyour email signature editor. Colors and label match the widget config so\nedits propagate everywhere.\n\n## Tips\n\n- If allowed-domains is set, the floating button respects it — but the\n  hosted page works regardless. So you can lock the widget to your site\n  and still share the URL freely.\n- Voice agents need a configured Vapi voice; check the agent's **Voice**\n  tab if calls fail to connect.\n- The button label, color, and icon are all live-previewed in the editor.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/click-to-call-widget","publishedAt":"2026-04-29T10:27:44.155Z","updatedAt":"2026-06-26T03:30:10.680Z"},{"slug":"settings-system-prompt-fallback","title":"Settings: system prompt, fallback, behaviour","summary":"The core identity of your agent — who it is, what it does, and what it says when it hits a dead end.","body":"The **Settings** tab is where you shape your agent's core identity. Everything else\n(Rules, Tools, Persona, etc.) layers on top of this.\n\n## System Prompt\n\nThe system prompt is the agent's job description. Keep it short, specific,\nand focused on the outcome you want.\n\n**Good:**\n\n```\nYou are a friendly inbound assistant for a beauty salon. You help contacts\nbook appointments, answer questions about services and pricing, and nudge\nhesitant leads toward booking. Your primary goal is to get a confirmed booking.\n```\n\n**Less good:**\n\n```\nYou are a helpful AI.\n```\n\nThe more context you give, the better the agent picks up on tone and\npriorities. Pre-filled templates give you a strong starting point — edit\nthem to match your business.\n\n## Behavioural Instructions\n\nThese are bullet-point rules the agent always follows. Think of them as\nnon-negotiable behaviours rather than narrative prompt content.\n\n```\n- Never quote prices you're not 100% sure about\n- If asked for a manager, immediately hand off\n- Match the contact's energy — casual if they're casual, formal if formal\n- Always confirm booking details back to the contact\n```\n\n## Fallback Behaviour\n\nWhat the agent does when it genuinely doesn't have an answer. Three modes:\n\n- **Say a message** — speaks a pre-written line. Use when you want a\n  consistent response (e.g. \"Let me check with the team and get back to you\").\n- **Transfer to human** — pauses the agent immediately and fires your\n  [human-handover notification](/help/a/human-handover-notifications).\n- **Say a message, then transfer** — both. Speaks the line, then escalates.\n\nThe fallback message supports [merge fields](/help/a/merge-fields) so you can\npersonalise: `Hi {{contact.first_name|there}}, let me check on that for you.`\n\n## Tips\n\n- If you find yourself adding the same instruction to every agent, it\n  probably belongs in the system prompt template itself — ping support.\n- Short + specific beats long + generic. Every extra line adds tokens and\n  dilutes focus.\n- When in doubt, test changes in the Playground before they go live.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/settings-system-prompt-fallback","publishedAt":"2026-04-20T13:51:50.550Z","updatedAt":"2026-06-26T03:29:58.607Z"},{"slug":"simple-vs-advanced-agents","title":"Simple vs Advanced agents: picking a context level","summary":"Advanced agents pre-load the contact's opportunities and custom fields into every turn. When to flip it on, what it costs, and when not to.","body":"Every agent is one of two context levels. It's set when you create the\nagent, shown on the agent's settings page, and can be flipped at any time —\nno data migration, no downtime.\n\n## The short version\n\n- **Simple** — the default. The agent sees the contact's name, tags, and\n  conversation history. That's it. Zero extra tokens per turn, zero extra\n  API calls to GoHighLevel.\n- **Advanced** — also sees the contact's recent opportunities and custom\n  fields on every turn, plus a [Business Context](/help/a/business-context-glossary)\n  glossary you write once. Costs more tokens per reply, but the agent can\n  reason about specific deals, products, or pricing without having to\n  stop and call a tool.\n\nIf your agent only handles generic questions (\"what are your hours?\",\n\"can I book an appointment?\"), **use Simple**. If your agent needs to\ndiscuss specific things the contact has already shown interest in\n(vehicles, properties, courses, product SKUs, pending quotes), **use\nAdvanced**.\n\n## What Advanced actually loads\n\nEvery time the agent replies, in addition to the usual prompt, it sees:\n\n1. **Your Business Context glossary** — the plain-English explanation\n   you wrote telling the agent what your custom fields and opportunities\n   represent. This is where you say things like \"Each opportunity is a\n   specific vehicle the contact has inquired about. monetaryValue is\n   the listed sale price in USD.\"\n2. **The contact's custom fields** — only the ones with values. Shown\n   as `field_key: value` pairs.\n3. **Open opportunities** — up to **8 most recent** live inquiries\n   (anything not won/lost/abandoned) from the last **~6 months**.\n   The section header includes the **subtotal** of every open\n   opportunity's monetary value so the agent sees revenue still in\n   play at a glance. Each line shows the name, price in USD, current\n   pipeline stage, and any custom fields on that opportunity\n   (`vehicle_color=red`, `vehicle_miles=42000`, etc.).\n4. **Won deals** — up to **5 most recent** completed sales within\n   the window, with a subtotal showing captured lifetime value.\n   Tells the agent \"we've already earned $X from this contact\" and\n   prevents it from pitching things the contact already bought.\n5. **Lost / abandoned** — up to **5 most recent** closed-lost or\n   abandoned deals in the window, with a subtotal showing missed\n   revenue. Each line says whether the status was `lost` (the\n   contact actively passed) or `abandoned` (went dark), so the\n   agent treats a re-pitch appropriately.\n\nIf any bucket has more opportunities than fit in its slice, the\nagent is told the exact number that were dropped and that it can call\n`get_opportunities` for anything it can't see directly.\n\n## What it looks like on a real turn\n\nTo make this concrete — here's the exact block that gets injected\ninto the system prompt for an Advanced agent at a used car dealer,\nwhere the contact has three live inquiries, one closed sale earlier\nthis year, and one deal they passed on:\n\n```\n## Business Context\nWe are a used car dealership. Each opportunity is a specific vehicle\nthe contact has inquired about. monetaryValue is the listed sale\nprice in USD. Custom fields starting with vehicle_ describe the car…\n\n## Contact Context\n### Custom fields\n- budget_cap: 40000\n- preferred_body_style: Truck\n\n### Open opportunities — 3 live inquiries, $132,000 still in play\n1. 2019 Ford F-150 4x4 — $45,000 — stage: test_drive_scheduled\n   vehicle_color=red, vehicle_year=2019, vehicle_miles=42000\n2. 2021 Toyota RAV4 LE — $35,000 — stage: interested\n   vehicle_color=silver, vehicle_year=2021, vehicle_miles=18000\n3. 2020 Ford F-250 — $52,000 — stage: new\n   vehicle_color=white, vehicle_year=2020, vehicle_miles=60000\n\n### Won deals — 1 closed in last 6 months, $18,500 captured\n1. 2015 Hyundai Accent — $18,500 — sold 2025-12-04\n   vehicle_color=blue, vehicle_year=2015, vehicle_miles=95000\n\n### Lost / abandoned — 1 in last 6 months, $22,000 missed\n1. 2018 Honda Accord — $22,000 — lost 2025-11-12\n```\n\nThe three-bucket split gives the agent explicit revenue context:\n\n- **$132,000 still in play** — pipeline the agent can move forward\n- **$18,500 captured** — don't re-offer what they already own, but\n  it's useful for \"how's the Accent treating you?\" small talk\n- **$22,000 missed** — the Accord is off the table, don't pitch it\n  again; use it as a signal about their taste\n\nWith that visible on every turn, the agent can write things like\n*\"The F-150 is $5k over your budget — want me to pull some trucks\nunder $40k to compare?\"* or *\"I see the Accord wasn't the right fit\nlast month — is size what pushed you toward trucks?\"* without\ncalling a tool.\n\n## Using merge fields against this data\n\n[Merge fields](/help/a/merge-fields) give you `{{token|fallback}}`\nplaceholders for pre-written templates (fixed-mode trigger messages,\nfollow-up steps, voice openers, fallback replies). Contact-level data\nin the Advanced context is available as merge tokens:\n\n- `{{contact.first_name|there}}` — the contact's first name\n- `{{custom.budget_cap|your budget}}` — contact custom field\n- `{{custom.preferred_body_style|something nice}}` — another one\n\nSo a fixed-mode trigger message authored as:\n\n```\nHi {{contact.first_name|there}}, we've got new {{custom.preferred_body_style|vehicles}}\nunder {{custom.budget_cap|your budget}} that just landed on the lot. Want to\ntake a look this week?\n```\n\n...renders for the contact above as:\n\n```\nHi Jamie, we've got new Truck under 40000 that just landed on the\nlot. Want to take a look this week?\n```\n\nNote the fallbacks — `|there`, `|your budget`,\n`|vehicles` — kick in for contacts where those fields are empty, so\nthe same template still reads naturally for a brand-new lead who\nhasn't had their budget captured yet.\n\n## Merge fields inside the glossary itself\n\nThe Business Context glossary **also runs through the merge-field\nrenderer** before it's handed to the LLM. So you can personalise the\nglossary per contact, not just pre-written messages:\n\n```\nYou are speaking with {{contact.first_name|the contact}}. Their budget\nis {{custom.budget_cap|not disclosed}} and their assigned salesperson\nis {{user.name|our team}} ({{user.phone|call the showroom}}).\n\nWe are a used car dealership. Each opportunity is a specific vehicle\nthe contact has inquired about. monetaryValue is the listed sale\nprice in USD…\n```\n\nAt runtime the agent sees resolved values: *\"You are speaking with\nJamie. Their budget is 40000 and their assigned salesperson is Alex\nChen (+1 415 555 0100).\"* The same token syntax you use in trigger\nmessages works inside the glossary.\n\nTokens available in the glossary:\n\n- `{{contact.first_name|fallback}}` and all [contact tokens](/help/a/merge-fields)\n- `{{custom.<fieldKey>|fallback}}` for contact custom fields\n- `{{user.name|fallback}}`, `{{user.email}}`, `{{user.phone}}` —\n  the contact's assigned team member\n- `{{date.today}}` / `{{date.tomorrow}}`\n\nClick any **Start from an example** chip in the Business Context\neditor to load a starter glossary that uses merge fields and\nfallbacks — easiest way to see the pattern is to pick one closest to\nyour industry and edit from there.\n\n## Merge fields vs opportunity details — an important distinction\n\n**Merge fields only resolve contact-level data.** There is no\n`{{opportunity.name}}` or `{{custom.vehicle_color}}` token — those\ndetails live on opportunities, not on the contact, and there can be\nmany per contact. Trying to merge them makes no sense (\"which one?\").\n\nInstead, **the AI references opportunities naturally** when it writes\nits own reply, because it's reading the same Active inquiries section\nyou saw in the injected block above. If the contact texts *\"is the\nred one still available?\"*, the agent resolves \"red one\" to the\nF-150 by cross-referencing `vehicle_color=red`, and writes back\nconversationally. You don't template that — you just rely on the\nagent seeing the data.\n\n**Rule of thumb:**\n\n- Pre-written template with a single contact in front of it → use\n  merge fields against contact-level data\n- AI-generated reply that references *specific* cars / deals / rooms\n  / properties the contact is looking at → use Advanced context and\n  let the agent compose freely\n\n## What stays the same regardless\n\nBoth Simple and Advanced agents see:\n\n- The contact's basic fields (name, phone, email, tags)\n- Your agent's system prompt and extra instructions\n- [Qualifying questions](/help/a/qualifying), [Rules](/help/a/rules),\n  [Listening rules](/help/a/listening), [Tools](/help/a/tools)\n- Prior conversation history\n- Agent persona + working hours\n\nAdvanced doesn't replace any of this — it adds commercial context on\ntop. Everything you'd tune on a Simple agent tunes the same way on an\nAdvanced one.\n\n## When to use Simple\n\n- Customer support — the contact's issue is in the message, not in the\n  CRM record\n- Booking-only agents — time-slot lookups don't need past-deal context\n- FAQ agents — the answers are in your knowledge base, not in the\n  contact's opportunities\n- High-volume outbound where token cost matters\n- Any agent where the contact is usually brand-new and has no deal\n  history to reason over\n\n## When to use Advanced\n\n- Car dealers — each opportunity is a vehicle, custom fields are specs,\n  monetary value is the listed price\n- Real estate agents — opportunities are properties shown, custom fields\n  are square footage / bedrooms / price band\n- B2B sales reps — opportunities are deals at different stages, custom\n  fields are deal attributes (seat count, contract length)\n- Quote-based services (trades, event vendors) — opportunities carry the\n  itemised quote, custom fields carry specs\n- Course and coaching providers — opportunities are programs the contact\n  has looked at\n- Anywhere a contact accumulates a **pipeline of specific things** and\n  the agent needs to reference them by detail (\"the red one\", \"the 2br\")\n\n## What it costs\n\nAdvanced is an opt-in because it isn't free:\n\n- **Tokens per turn** — expect a few hundred extra tokens per reply,\n  depending on how many opportunities and custom fields the contact has.\n  On a lean contact (1–2 opportunities, a handful of fields), it's\n  negligible. On a maxed-out snapshot (8 active + 5 closed with lots of\n  custom fields each), it can add ~800–1500 tokens.\n- **CRM API calls** — three extra calls on each turn: fetch\n  opportunities, fetch contact custom-field definitions (to hydrate\n  keys), fetch opportunity custom-field definitions. All three are\n  parallelised, so they add about one round-trip of latency in the\n  worst case.\n\nNo billing impact beyond normal token usage. If you hit GHL's rate\nlimit it'll be from a different workflow — the extra reads are light.\n\n## How to switch\n\nFrom the agent's base **Settings** page, the **Context Level** section\nhas a Simple / Advanced toggle. Flip it and hit Save. Changes take\neffect on the *next* inbound — no downtime, no re-indexing.\n\nAdvanced-only fields (like your Business Context glossary) stick around\nin the database even if you flip back to Simple, so you can toggle\nfreely during testing. When the agent is Simple, the glossary is just\ndormant.\n\n## When to pick at creation vs later\n\nYou'll pick a level in the new-agent wizard's **Build** step. Default\nis Simple. There's no penalty to starting Simple and upgrading later,\nand no penalty to starting Advanced and discovering you don't need it.\nPick whichever matches how you imagine the agent's first real\nconversation going — you can always swap.\n\n## Duplicating keeps the level\n\nWhen you [duplicate an agent](/help/a/settings-system-prompt-fallback)\nor save it as a template, both the Context Level and the Business\nContext glossary come with it. Great for multi-location setups where\nevery dealership or every clinic uses the same glossary with minor\ntweaks.\n\n## Tool use isn't replaced\n\nEven with Advanced on, your agent still has its normal tool palette\n(`get_opportunities`, `get_contact_details`, etc.). Advanced is\nabout what the agent **knows without having to ask**. Tools are still\nthere for anything outside the pre-loaded snapshot (deeper history,\nfresh stage lookups, cross-contact searches). The trade-off isn't\n\"context vs tools\" — it's \"start with context *then* tools if\nneeded.\"","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/simple-vs-advanced-agents","publishedAt":"2026-04-21T07:15:21.047Z","updatedAt":"2026-06-26T03:30:09.674Z"},{"slug":"business-context-glossary","title":"Writing a Business Context glossary","summary":"The free-text block that tells your Advanced agent what your custom fields and opportunities mean in your business.","body":"The **Business Context** textarea only appears for\n[Advanced agents](/help/a/simple-vs-advanced-agents). It's a free-text\nexplanation of your business that gets injected at the top of the\nagent's system prompt on every turn, right before the contact data.\n\nIts job is to turn raw CRM values into meaningful information. Without\na glossary, the agent sees this:\n\n```\nOpportunity: 2019 Ford F-150 4x4 — $45,000 (open) stage: 8H2aKLmq\n  vehicle_color=red, vehicle_year=2019, vehicle_miles=42000\n```\n\n...and has to guess what any of it means. With a glossary, it knows\nthat monetaryValue is the listed sale price in USD, that\n`vehicle_*` custom fields are car specs, and that the stage ID\ncorresponds to \"Test Drive Scheduled\".\n\n## What to include\n\nA good glossary answers these questions:\n\n1. **What is your business?** One sentence. *\"We are a used car\n   dealership in Brisbane.\"*\n2. **What does an opportunity represent?** Especially when it's not\n   obviously a \"deal.\" *\"Each opportunity is a specific vehicle the\n   contact has inquired about. One contact usually has 2–5 active\n   opportunities as they compare cars.\"*\n3. **What does monetaryValue mean?** *\"Listed sale price in USD, not\n   the negotiated price.\"*\n4. **What do your custom field groups mean?** *\"Custom fields starting\n   with vehicle_ describe the car: vehicle_stock_id, vehicle_vin,\n   vehicle_make, vehicle_model, vehicle_year, vehicle_color,\n   vehicle_miles.\"*\n5. **What are your pipeline stages?** *\"Stages progress: New Inquiry →\n   Test Drive Scheduled → Test Driven → Offer Made → Financing → Sold.\n   A 'lost' status means they bought elsewhere or decided against.\"*\n6. **How should the agent reference things naturally?** *\"When the\n   contact says 'that truck' or 'the silver one', cross-reference their\n   active inquiries and pick the match by vehicle_color.\"*\n\nYou don't have to hit every one of those. Include only what the agent\nwill actually trip on without.\n\n## Worked example: used car dealer\n\n```\nWe are a used car dealership. Each opportunity is a specific vehicle\nthe contact has inquired about — a single contact will usually have\n2–5 active opportunities as they compare options. monetaryValue is\nthe listed sale price in USD (not the negotiated price).\n\nCustom fields on opportunities describe the vehicle:\n- vehicle_stock_id: our internal stock number (always starts with \"S-\")\n- vehicle_make, vehicle_model, vehicle_year: self-explanatory\n- vehicle_color, vehicle_miles: self-explanatory\n\nContact-level custom fields:\n- budget_cap: contact's max budget in USD\n- preferred_body_style: sedan / SUV / truck / wagon\n- trade_in_vehicle: free-text description of what they're trading\n\nPipeline stages (in order): New Inquiry → Viewing Scheduled →\nViewed → Test Drive Scheduled → Test Driven → Offer Made →\nFinancing → Sold. A \"lost\" opportunity means they went elsewhere or\npassed on it. A \"won\" opportunity is a completed sale.\n\nWhen the contact says \"that truck\", \"the red one\", \"the silver RAV4\",\netc., cross-reference their active inquiries and pick the match.\nIf they ask about a vehicle not in their active inquiries, call\nsearch_opportunities to see if it's in stock.\n```\n\n## Worked example: B2B SaaS sales rep\n\n```\nWe sell a team productivity SaaS on monthly and annual plans. Each\nopportunity is a deal in a specific pipeline stage; monetaryValue is\nthe annualised contract value in USD.\n\nOpportunity custom fields:\n- seat_count: number of user licences being discussed\n- plan_tier: \"Starter\", \"Pro\", or \"Enterprise\"\n- contract_length_months: typically 12 or 36\n- primary_use_case: the main workflow they want to solve\n\nContact custom fields:\n- role: usually \"Founder\", \"Ops Manager\", or \"VP Engineering\"\n- company_size_band: 1-10, 11-50, 51-200, 201+\n- current_tool: what they're using today (often Asana, Monday, or none)\n\nStages: Discovery → Demo Scheduled → Demo Done → Proposal Sent →\nVerbal Yes → Legal Review → Signed. Lost usually means they went\nwith a competitor (logged in current_tool on close).\n\nIf the contact references \"the proposal\", check for an opportunity in\nstage Proposal Sent and cite its monetaryValue + contract_length_months.\nIf they're weighing tiers, the plan_tier field tells you which one\nthey're considering on each open deal.\n```\n\n## Worked example: trades / quote-based service\n\n```\nWe're a residential plumbing contractor. Opportunities are itemised\nquotes — monetaryValue is the total quoted price in USD including GST.\n\nOpportunity custom fields:\n- job_type: \"Emergency\", \"Renovation\", \"Maintenance\", \"New install\"\n- address: service address (not always the contact's home address)\n- materials_cost: parts-only portion of the total\n- labour_hours_estimated: our crew time estimate\n\nContact custom fields:\n- preferred_contact_window: contact-provided time they want a call\n- access_notes: keys, gate codes, dogs, parking — free text the tech\n  needs before arrival\n- property_type: \"House\", \"Apartment\", \"Commercial\"\n\nStages: Quote Requested → Quoted → Quote Accepted → Scheduled →\nIn Progress → Complete → Invoice Sent → Paid. A \"lost\" opportunity\nmeans they went with another quote.\n\nWhen the contact references \"the quote\" or \"the bathroom job\", pick\nthe most recently quoted opportunity. If they ask for a timeline,\ncheck the stage first — \"Scheduled\" opportunities have an associated\nappointment you can look up.\n```\n\n## How to write it well\n\n- **Be specific, not decorative.** The glossary is a reference doc for\n  the agent, not marketing copy. Skip adjectives, include field names.\n- **Name the fields exactly as they appear.** If your GHL custom field\n  key is `contact.inquired_vehicle_id`, use that exact string. The\n  agent matches on the keys it sees in the data.\n- **Describe the units.** \"USD\" beats \"dollars\". \"monthly\" beats\n  \"recurring\". \"mm/dd/yyyy\" beats \"a date\".\n- **Give the agent permission to cross-reference.** Say things like\n  \"When the contact says X, look at Y.\" Without the hint, the agent\n  often won't make the connection.\n- **Keep it under ~500 words.** It's injected every turn, so shorter\n  is cheaper. If you need more structure, split it into sections with\n  `##` markdown headers.\n\n## Common mistakes\n\n- **Writing it as persona instructions.** The glossary describes the\n  *data*, not the *voice*. Tone, formality, emojis, and style belong\n  on the [Persona](/help/a/persona) page, not here.\n- **Listing every field in GHL.** Only fields the agent will encounter\n  are worth documenting. If no contact has a `second_drivers_licence`\n  field populated, the agent never sees it and the glossary line is\n  wasted.\n- **Hardcoding pricing.** Put prices in your [Knowledge base](/help/a/knowledge),\n  not here. Pricing changes — you don't want to re-save every agent\n  when a tier goes up $5.\n- **Describing workflow instead of data.** \"When the contact agrees to\n  a demo, book a slot\" is a behaviour instruction, not a glossary\n  entry. That belongs in **Extra Instructions**.\n\n## When to update it\n\nUpdate the glossary when:\n\n- You add a new custom field category in GHL that opportunities will\n  carry\n- You rename a pipeline stage\n- The meaning of an existing field shifts (e.g. monetaryValue starts\n  including tax when it didn't before)\n- Your agent misinterprets something the same way twice — odds are\n  the glossary didn't tell it how\n\nYou don't need to touch it when:\n\n- Your knowledge base updates (it's a separate layer)\n- Rules or listening categories change\n- You add a new channel or adjust working hours\n\n## Testing\n\nUse the Playground to simulate a conversation with a real contact ID.\nThe agent's system prompt (including your glossary and the live\ncontact data) is deterministic — if the agent can't answer \"how much\nis the red one?\" when the red F-150 is clearly in the contact's\ninquiries, the fix is almost always in the glossary or the custom\nfield names.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/business-context-glossary","publishedAt":"2026-04-21T07:15:21.432Z","updatedAt":"2026-06-26T03:30:11.191Z"},{"slug":"mcp-connectors-overview","title":"MCP connectors: what they are and when to use them","summary":"Connect external tools (Meta Ads, Stripe, Linear, anything with an MCP server) and write plain-English rules for when your agent should use them.","body":"**MCP** stands for Model Context Protocol — an open standard for letting\nLLMs call external tools. We use it to plug your CRM agent into anything\nthat exposes an MCP server: Meta Ads, Stripe, Linear, your own internal\nAPIs, third-party services.\n\n## Why it matters\n\nBuilt-in tools cover the common CRM flows — booking, tagging, sending\nmessages, updating opportunities. MCP covers everything else.\n\nA few examples we've seen:\n\n- **Meta Ads** — a contact texts about ad performance. The agent fetches\n  ROAS for the last 7 days and replies with the numbers.\n- **Stripe** — a customer asks about a charge. The agent looks up the\n  invoice, confirms the amount, and replies.\n- **Linear** — a contact reports a bug. The agent files a ticket and\n  references the ticket number in the reply.\n- **Your internal API** — anything you've already built that you want\n  the agent to call.\n\n## How it works\n\nThree pieces:\n\n1. **Workspace-level connection** — you connect an MCP server once\n   (server URL + auth token). Stored encrypted at rest.\n2. **Per-agent attachment** — for each agent, you pick which of the\n   server's tools should be available to that agent.\n3. **Per-tool rules** — for each enabled tool, you write a plain-English\n   \"when should the agent use this?\" instruction. The agent reads this\n   every turn and decides whether the situation matches.\n\nThe actual tool execution happens via Anthropic's hosted MCP — we pass\nthe server config through, Claude calls the tool, the result comes\nback inline. We log every call so you can audit.\n\n## What gets logged\n\nEvery MCP tool invocation shows up in the agent's **Integrations → Logs**\nsub-tab as `mcp:server-name:tool-name` alongside the original\nconversation. You can see who triggered it, when, and which tool fired.\n\n## Where to start\n\n- [Connect an MCP server](/help/a/mcp-connectors-connect)\n- [Write rules for when the agent should use a tool](/help/a/mcp-connectors-rules)\n\n## Curated vs custom\n\nWe ship one-click cards for **Meta Ads**, **Stripe**, and **Linear** with\nsensible default URLs and auth helper text. Anything else? Use the\n**Custom MCP server** option and paste an HTTP MCP URL. Anything that\nspeaks JSON-RPC over HTTP works.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/mcp-connectors-overview","publishedAt":"2026-04-29T10:27:44.536Z","updatedAt":"2026-06-26T03:30:09.137Z"},{"slug":"channels","title":"Channels: where your agent runs","summary":"SMS, WhatsApp, Instagram, Facebook, Google Business, Live Chat, Email. Pick the channels your agent listens on.","body":"The **Channels** tab controls which messaging channels your agent is\ndeployed on. An agent with no channels won't receive anything — it shows\nas \"Active · No channels\" in the header.\n\n## How it works\n\nEach channel is a toggle. When ON, the agent responds to inbound messages\non that channel through your connected CRM.\n\n- **SMS** — text messages via GoHighLevel\n- **WhatsApp** — WhatsApp Business via GHL\n- **Facebook Messenger** — page DMs\n- **Instagram DMs** — Instagram inbox\n- **Google Business** — Google Business Profile messages\n- **Live Chat** — your website chat widget\n- **Email** — email conversations via GHL\n\n## Voice is separate\n\nVoice calls are configured on the **Voice** tab, not here. Voice needs its\nown phone number, voice settings, and call-specific behaviour — it doesn't\nshare state with messaging channels.\n\n## When you'd want multiple agents\n\nIf you have very different conversations per channel (e.g. SMS is about\nbooking, live chat is about technical support), run **separate agents per\nchannel** rather than one agent everywhere. Use the [Deploy rules](/help/a/deploy-rules)\ntab to route the right inbound to the right agent.\n\n## Agent status decoder\n\nThe header shows one of three states:\n\n- **Live** — active and deployed on at least one channel\n- **Active · No channels** — running but nothing points at it\n- **Paused** — you clicked Pause or hit a stop condition","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/channels","publishedAt":"2026-04-20T13:51:50.950Z","updatedAt":"2026-06-26T03:30:05.459Z"},{"slug":"mcp-connectors-connect","title":"Connect an MCP server","summary":"Step-by-step: pick a curated integration or paste a custom URL, add auth, and discover the available tools.","body":"MCP servers are connected at the workspace level (one connection serves\nevery agent in the workspace) and attached at the agent level (each agent\npicks which tools to enable).\n\n## Connect a server\n\n1. Open any agent → **Integrations** tab\n2. Click **+ Connect MCP**\n3. Pick a curated card (Meta Ads, Stripe, Linear) **or** click\n   **Custom MCP server** to paste a URL\n4. The form pre-fills with sensible defaults. Add your auth token:\n   - **Bearer token** for most servers (paste the raw token; we add the\n     `Authorization: Bearer …` header)\n   - **Custom header** if the server uses a non-bearer scheme (paste in\n     `Header-Name: value` format)\n   - **No auth** for open/internal MCPs\n5. Click **Connect & discover tools**\n\nWe immediately call the server's `tools/list` endpoint and cache the\nresult. You'll see the discovered tools listed under the server card.\n\n## Where to find auth tokens\n\n- **Meta Ads** — generate a Marketing API access token with `ads_read`\n  + `ads_management` scopes ([Meta docs](https://developers.facebook.com/docs/marketing-api/get-started))\n- **Stripe** — use a restricted API key (`sk_live_…` or `rk_live_…`).\n  Read-only is safest unless you want refunds. ([Stripe dashboard](https://dashboard.stripe.com/apikeys))\n- **Linear** — generate a personal API key in\n  [Linear → Settings → API](https://linear.app/settings/api)\n\n## Re-discovering tools\n\nIf the server adds new tools, click **Re-discover tools** on the server\ncard to refresh the cached list.\n\n## Per-agent attachment\n\nDiscovered tools are not automatically active for any agent. To enable a\ntool on an agent:\n\n1. Toggle the tool **on** in the Integrations tab\n2. Write a \"when to use\" rule (see [the rules article](/help/a/mcp-connectors-rules))\n\nEvery tool starts disabled by default — you opt each one in deliberately.\n\n## Security model\n\n- Auth tokens are encrypted at rest with AES-256-GCM, keyed by an env\n  var (`SECRETS_ENCRYPTION_KEY`). They never appear in the dashboard\n  after creation, only as a masked indicator.\n- The token is only sent at request-time when Anthropic calls the MCP\n  server on your behalf.\n- Detaching a tool removes the agent's access immediately. Deleting the\n  server cascades to remove all attachments across all agents.\n\n## Troubleshooting\n\n- **\"MCP server returned 401\"** — the token is wrong or expired. Edit\n  the server and paste a fresh one.\n- **\"No tools discovered\"** — the server probably doesn't expose\n  `tools/list`. Most modern MCPs do; some custom servers don't.\n- **The agent never calls the tool** — see\n  [writing rules](/help/a/mcp-connectors-rules); usually the \"when to\n  use\" text is too generic.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/mcp-connectors-connect","publishedAt":"2026-04-29T10:27:44.909Z","updatedAt":"2026-06-26T03:30:00.753Z"},{"slug":"mcp-connectors-rules","title":"Writing rules: when should the agent use a tool?","summary":"Plain-English \"when to use\" descriptions, optional keyword gates, and the require-approval flag — how to steer the agent without coding.","body":"Connected tools are inert until you write rules for when the agent\nshould use them. The rule is what turns a generic API into \"the agent\nfetches Meta Ads ROAS the moment a customer asks about ad performance\".\n\n## The \"when to use\" rule\n\nThis is the most important field. Plain English, specific, with concrete\ntrigger phrases. The agent reads this every turn and decides whether the\nsituation matches.\n\n**Strong rules** describe the *signal* in the conversation, not the\n*action* of the tool:\n\n```\nWhen the contact asks about ad performance, ROAS, CPM, CTR, spend, or\nconversion numbers for the last 7/30 days.\n```\n\n**Weak rules** are too vague:\n\n```\nUse this for ad data.\n```\n\nCommon patterns that work well:\n\n- \"When the contact mentions [specific words / topics]\"\n- \"When the contact asks for [specific output]\"\n- \"Only when the contact provides a [specific identifier — order ID,\n  customer email, etc.]\"\n- \"Never call this unless the contact has explicitly [confirmed /\n  authorized / asked]\"\n\n## Required keywords (optional gate)\n\nComma-separated list. If set, the tool is **completely hidden** from the\nagent unless at least one keyword appears in the inbound message\n(case-insensitive). This is a hard gate — useful for tools you only ever\nwant fired in specific contexts.\n\n```\nads, campaign, roas, spend, cpm, conversion\n```\n\nWhen to use the gate:\n\n- The tool is destructive or expensive (\"pause campaign\" — only fire\n  when the user clearly mentions a campaign)\n- The tool would cause confusion if it ever ran by mistake\n- The agent has been over-eagerly calling the tool in unrelated contexts\n\nWhen **not** to use the gate:\n\n- Most read-only tools — the \"when to use\" rule is enough\n- Anything where natural language varies a lot (\"look up my account\"\n  doesn't always include the word \"account\")\n\n## Require human approval\n\nToggle this on for tools where you want a human to confirm before the\nagent fires. When set:\n\n- The agent is told in its system prompt: \"Before calling this tool,\n  tell the contact you're checking with the team and stop. Do not\n  invoke until the team has confirmed.\"\n- The agent's reply will end with \"Let me check with the team\" rather\n  than firing the tool\n\nThis is currently a **soft constraint** — enforcement is via the prompt\nto the model, not via execution interception. We're tracking a stricter\nhard-stop variant for high-risk tools as a follow-up.\n\n## A worked example\n\nConnecting Meta Ads with three tools:\n\n| Tool | When to use | Keywords | Approval? |\n|------|-------------|----------|-----------|\n| `get_campaign_performance` | Contact asks for ROAS, CTR, CPM, spend, or conversion numbers for any time window. | ads, campaign, roas, spend | No |\n| `pause_campaign` | Contact reports their ads are spending too fast OR explicitly asks to pause a named campaign. | pause, stop, halt | Yes |\n| `suggest_optimizations` | Performance is below the contact's stated target and the contact asks what to change. | improve, optimize, fix, why | No |\n\nResult: the agent reads conversation, fetches numbers freely when asked,\nsuggests changes when prompted, and never pauses anything without a\nhuman in the loop.\n\n## Iterating on rules\n\nUse [Replay & Fork](/help/a/replay-and-fork) to test rule changes against\nreal past conversations before pushing live. Append a candidate rule in\nthe Replay editor's \"additional instructions\" field and see what the\nagent would have said.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/mcp-connectors-rules","publishedAt":"2026-04-29T10:27:45.285Z","updatedAt":"2026-06-26T03:30:13.120Z"},{"slug":"replay-and-fork","title":"Replay & Fork: rerun any past conversation through new rules","summary":"Pick a past inbound, optionally override the system prompt or append a candidate rule, and see what the agent would have said. Pure dry run — no sends, no writes.","body":"Tuning agents in production is risky if you're flying blind. **Replay**\nlets you re-run any past inbound through any version of your prompt or\nrules and see, side-by-side, exactly what the agent would have said.\n\nOpen it from any agent → **Replay** tab.\n\n## What it does\n\nFor any MessageLog entry, replay:\n\n1. Reconstructs the conversation up to that inbound\n2. Re-runs the agent with current settings (or your overrides)\n3. Shows the original reply alongside the new reply, plus tools each\n   version called\n\nIt's a complete dry run:\n\n- No SMS / email / chat sends\n- No CRM writes (every write tool no-ops with a sandbox marker)\n- No MessageLog row created\n- No charges to your monthly usage cap (other than the LLM tokens for\n  the replay itself)\n\n## Workflow: tuning a system prompt\n\n1. Open Replay\n2. Pick an inbound the agent handled poorly\n3. Click **Overrides → Override system prompt**\n4. Paste your candidate prompt\n5. Click **Replay**\n6. Compare the original vs new reply\n\nIterate until you're happy, then update the agent's actual system prompt\nwith the winning version.\n\n## Workflow: testing a candidate rule\n\nYou wrote a new rule (e.g. \"Always offer Tuesday slots first\") and want\nto know if it would actually fire on real conversations.\n\n1. Open Replay\n2. Pick a conversation where the rule should have fired\n3. **Overrides → Append additional instructions**\n4. Paste the candidate rule\n5. Click **Replay** and check if the agent followed it\n\nThis is faster than adding the rule to the agent, hoping the next\ninbound exercises it, and reverting if not.\n\n## Workflow: spotting regressions\n\nBefore pushing a big prompt change, replay 5–10 of your most recent\nconversations. If the new prompt produces *worse* replies on the easy\ncases, that's a red flag — even if it fixes the hard one you started\nwith.\n\n## Limits\n\n- Replay uses message history reconstructed from MessageLog rows, not\n  the literal raw turn-by-turn record. Outbound replies are included as\n  assistant turns; tool calls aren't replayed (we don't re-execute\n  every `get_calendar_events` from history).\n- Tools that need real CRM data still hit your CRM (read-only) so the\n  agent can reason. Writes are sandboxed.\n- Long conversations only include the last ~8 turns of context — same\n  truncation as production.\n\n## Tips\n\n- The contactId is mangled (`playground-replay-…`) so write tools\n  no-op. You don't need to worry about contaminating real records.\n- The \"tools used\" chip lists each tool the new agent called; useful\n  for spotting \"the agent skipped get_available_slots\" type bugs.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/replay-and-fork","publishedAt":"2026-04-29T10:27:45.660Z","updatedAt":"2026-06-26T03:30:07.531Z"},{"slug":"knowledge","title":"Knowledge base","summary":"Give the agent things it needs to know — pricing, FAQs, policies, a full website crawl.","body":"The Knowledge tab is where you add context the agent draws on during\nconversations. Think of it as the set of documents a new team member would\nskim on their first day.\n\n## Three ways to add knowledge\n\n1. **Write it yourself** — paste a title + markdown body. Great for\n   pricing sheets, FAQ lists, one-liner policies.\n2. **Upload a file** — PDF, DOCX, or TXT. We extract the text and chunk it.\n3. **Crawl a website** — enter a URL, we fetch the page + its links. Set up\n   a recurring crawl to keep it fresh.\n\n## How the agent uses it\n\nOn every inbound message, we search the knowledge base for chunks\nsemantically related to what the contact just said, and attach the top\nmatches to the agent's context. It's not \"read everything always\" — the\nagent gets what's relevant to *this* turn.\n\n## What to put in\n\n**Good candidates:**\n- Pricing, packages, service menus\n- FAQ — common questions with authoritative answers\n- Business hours, location, contact info (beyond what's on the website)\n- Policies — cancellations, refunds, deposits\n- Product specs, SKUs, features\n\n**Bad candidates:**\n- Huge marketing pages (high token cost, low signal)\n- Blog posts unless they answer FAQs\n- Internal operations docs the agent shouldn't reveal\n\n## Recurring crawls\n\nFor pages that change (pricing, availability), schedule a recurring crawl —\ndaily or weekly. We only re-index when content has actually changed, so\nyour token bill doesn't climb for pages that stay still.\n\n## Deletion\n\nRemove a knowledge entry and it stops being used immediately. There's no\ncaching — next inbound message, it's gone from the agent's context.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/knowledge","publishedAt":"2026-04-20T13:51:51.329Z","updatedAt":"2026-06-26T03:30:04.976Z"},{"slug":"ai-judge","title":"AI Judge: pre-screen flagged messages so humans only see the hard ones","summary":"A small LLM reviews each draft reply that the rules engine flagged for approval. SAFE → auto-release; UNSAFE → optionally auto-block; UNCERTAIN → human review.","body":"The approval queue is a great safety net — but most flagged messages\nare perfectly fine, and reviewing every one is exhausting. The **AI\nJudge** runs a cheap LLM pass on each flagged draft and decides what to\ndo with it. Most operators see queue volume drop ~80% the day they\nturn it on.\n\nOpen it from **Approvals → 🤖 AI Judge settings**.\n\n## How it works\n\nWhen the existing rules engine flags a draft for approval (low sentiment,\nfirst contact, refund mention, etc.), the judge:\n\n1. Reads the inbound message and the draft reply\n2. Reads your custom rubric (optional, see below)\n3. Returns one of: **SAFE**, **UNSAFE**, or **UNCERTAIN** with a\n   one-line reason\n4. The platform decides what to do based on your per-agent settings\n\n## Verdict routing\n\nPer-agent toggles in the AI Judge settings modal:\n\n| Verdict | If `judgeAutoSend` ON | If OFF |\n|---------|------------------------|--------|\n| SAFE | **Released automatically** + sent to contact | Stays in queue for human |\n| UNSAFE | (depends on autoBlock) | Stays in queue for human |\n| UNCERTAIN | **Always** stays in queue | Always stays in queue |\n\n| Verdict | If `judgeAutoBlock` ON | If OFF |\n|---------|--------------------------|--------|\n| UNSAFE | **Auto-rejected**, never sent | Stays in queue for human |\n\nRecommended starting config:\n\n- **`judgeAutoSend`: ON** — SAFE verdicts release without a human.\n  This is where the queue-volume reduction comes from.\n- **`judgeAutoBlock`: OFF** — UNSAFE messages still surface to a\n  human until you've watched the judge's verdicts for a few days and\n  trust them.\n\n## The rubric\n\nCustom rubric (optional) is where you encode your specific policies.\nThe judge reads this on every call. Examples:\n\n```\n- Never auto-send anything that quotes a price\n- Auto-send anything that's just confirming a meeting time\n- UNSAFE: any reply that promises a refund or guaranteed outcome\n- UNSAFE: any reply that mentions specific dollar amounts\n- UNCERTAIN: anything mentioning a competitor by name\n```\n\nThe rubric is per-agent. Different agents can have different policies.\n\n## Models\n\n- **Haiku** (default) — fast, ~30× cheaper than Sonnet, great for\n  routine messages\n- **Sonnet** — slower, more expensive, better at nuanced cases (legal,\n  medical, complex business contexts)\n\nMost operators run Haiku across all agents.\n\n## What you see in the queue\n\nEvery pending and decided row in the approval queue now shows the\njudge's verdict as a chip — green for SAFE, red for UNSAFE, blue for\nUNCERTAIN. Hover for the judge's one-line reason.\n\nIf you reject a SAFE-judged message, that's a signal the rubric needs\ntightening. Add the case to the rubric and the judge will catch it\nnext time.\n\n## Cost\n\nEach flagged message costs ~1 Haiku call (a few hundred tokens). For a\nworkspace with 100 daily flagged messages, that's pennies — and you save\nthe operator hours of review time.\n\n## Failure mode: fail-open\n\nIf the judge call fails (API timeout, model error), the message stays\nin the queue for human review. The judge **never** auto-rejects on its\nown error. You can't get worse outcomes by enabling it — only the same\nor better.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/ai-judge","publishedAt":"2026-04-29T10:27:46.034Z","updatedAt":"2026-06-26T03:30:03.894Z"},{"slug":"deploy-rules","title":"Deploy rules: when the agent runs","summary":"Decide which conversations this agent picks up. AND, OR, and NOT across tags, stages, keywords.","body":"The **Deploy** tab defines *when* this agent runs on an inbound message.\nThink of it as the door policy — who gets let in.\n\n## The mental model\n\n- Every workspace can have multiple agents\n- When an inbound message arrives, we evaluate each agent's deploy rules\n  **in priority order**\n- The first agent whose rules match catches the message\n- If no agent matches, the message goes unanswered (intentional — better than\n  the wrong agent replying)\n\n## Rule shape\n\nEach rule is one or more **groups**. The boolean logic is:\n\n- **Within a group → AND.** Every condition in the group must match.\n- **Between groups → OR.** Any one group matching is enough.\n- **Each condition → NOT (optional).** Click the NOT toggle on a condition\n  to invert it (*does NOT have tag*, *NOT in pipeline stage*, etc.).\n- **Within a condition → OR.** List multiple values and any one matches.\n\n**Example — one group, two conditions:**\n\n```\nContact has tag in [hot-lead, vip]\nAND\nContact does NOT have tag [bot, do-not-contact]\n```\n\nReads as: *\"Run this agent for any contact tagged hot-lead or vip, as\nlong as they don't also have bot or do-not-contact.\"*\n\n**Example — two groups (OR):**\n\n```\nGroup 1:\n  Contact has tag [enterprise]\n  AND Contact in pipeline stage [closing]\nOR\nGroup 2:\n  Contact has tag [high-intent]\n  AND NOT Contact has tag [cold]\n```\n\nReads as: *\"Run this agent for enterprise deals in closing stage — OR —\nhigh-intent contacts who aren't tagged cold.\"*\n\n## Condition types\n\n- **All inbound messages** — catch-all, matches everything (doesn't\n  support NOT — negating \"everything\" means \"nothing\")\n- **Contact has tag** — picks from your GHL tags (multi-select, supports NOT)\n- **Contact in pipeline stage** — pipeline stage ID (multi-value, supports NOT)\n- **Message contains keyword** — keyword match against the inbound\n  (multi-value, supports NOT)\n\n## Priority order\n\nRules are evaluated lowest-priority number first. By convention:\n- Very specific rules → priority 10–50\n- Catch-all fallback → priority 999\n\nThis way your \"hot-lead\" agent catches its contacts before the generic\nagent scoops them up. A rule that's purely `ALL inbound messages` lands\nat priority 999 automatically; anything more specific (including `ALL`\ncombined with a tag filter) lands at priority 10 so it can outrank a\nplain catch-all.\n\n## Design tips\n\n- **Keep rules layered.** One specific rule per segment, one catch-all.\n- **Avoid overlap.** If two agents could both match, the first wins by\n  priority. Test with the Routing Diagnostic tool (in the left sidebar)\n  if you're unsure which agent would catch a given contact.\n- **Use NOT to carve out exceptions.** Instead of writing three separate\n  rules for \"VIP but not cold, VIP but not churned, VIP but not bot\",\n  one rule with three NOT clauses is cleaner and sorts better.\n- **Use OR groups for \"either of these makes sense\".** A nurture agent\n  for \"long inactivity OR explicit re-engagement request\" reads better\n  as two groups than one overloaded condition set.\n- **Between whole rules is still OR.** Rule 1 fires OR rule 2 fires — not\n  AND. Prefer OR groups within one rule over two separate rules when the\n  logic is conceptually one door policy; use separate rules when they\n  truly are different scenarios with different priorities.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/deploy-rules","publishedAt":"2026-04-20T13:51:51.709Z","updatedAt":"2026-06-26T03:29:59.680Z"},{"slug":"merge-fields","title":"Merge fields: the {{…}} placeholders that personalise pre-written messages","summary":"Drop contact data into fixed-mode triggers, follow-ups, voice openers, fallback lines, and the Advanced business-context glossary.","body":"Merge fields let you write one message template and have it render\ndifferently per contact. Type `{{contact.first_name}}` in a follow-up,\nand at send time it becomes \"Hi Jamie\" or \"Hi Alex\" depending on whose\nnumber is on the other end.\n\n## Where they work\n\nAnywhere you're writing a **pre-written template** — not anywhere the\nAI composes its own reply.\n\n- **Fixed-mode trigger messages** (Triggers tab, when \"Fixed message\"\n  is selected)\n- **Follow-up steps** (Follow-ups tab — each step's message body)\n- **Voice opener / closer / end-of-call phrase** (Voice tab)\n- **Fallback message** (Settings tab, when behaviour is \"Send a\n  message\" or \"Message then transfer\")\n- **Widget welcome message** (Widget config)\n- **Qualifying question text** (Qualifying tab)\n- **Business Context glossary** on [Advanced agents](/help/a/simple-vs-advanced-agents)\n  — the glossary itself runs through the renderer, so `{{user.name}}`\n  in your glossary resolves to the contact's assigned salesperson\n\nThe AI's own replies don't need merge fields because the agent already\nsees the contact data and personalises naturally. Writing\n`{{contact.first_name}}` in the system prompt is usually redundant.\n\n## Syntax\n\n```\n{{token}}                       → empty string if missing\n{{token|fallback text}}         → \"fallback text\" if missing\n```\n\nThe token path uses dots: `{{namespace.key}}`. The optional `|fallback`\nafter a pipe renders in place of an empty or missing value.\n\n**Always use a fallback on anything that might be empty.** First names,\ncustom fields, and calls from unknown numbers can all hit a blank.\n`{{contact.first_name|there}}` reads naturally in both cases.\n\n## The tokens\n\n### Contact\n\n- `{{contact.first_name|fallback}}` — first name, or extracted from\n  `name` if no firstName\n- `{{contact.last_name|fallback}}` — last name\n- `{{contact.full_name|fallback}}` — whole name\n- `{{contact.email|fallback}}` / `{{contact.phone|fallback}}`\n- `{{contact.company|fallback}}` / `{{contact.city|fallback}}` /\n  `{{contact.state|fallback}}` / `{{contact.country|fallback}}`\n- `{{contact.tags|fallback}}` — comma-joined list\n\n### Custom fields (contact-level only)\n\n`{{custom.<fieldKey>|fallback}}` resolves against the contact's GHL\ncustom fields. The `<fieldKey>` is the stable slug from Settings →\nCustom Fields (usually `contact.your_field_name` in GHL). The\n`{{…}} Insert value` picker pre-populates with the real field keys\nfrom your location so you don't have to type them.\n\n**Note:** There's no `{{opportunity.*}}` or `{{custom.vehicle_color}}`\nfor opportunity-level custom fields — opportunities can be multiple per\ncontact (which one would merge?). See [Advanced agents](/help/a/simple-vs-advanced-agents)\nfor how the AI reads opportunity data directly instead.\n\n### Agent\n\n- `{{agent.name|fallback}}` — the agent's display name (or persona\n  name if set)\n\n### Assigned user (contact's CRM owner)\n\nThe team member assigned to the contact in GHL. Requires the OAuth\nscope `users.readonly` — reconnect GHL from Integrations if the\nvalues come back empty. Useful for \"your rep is Alex at\n+1 415 555 0100\" style templates.\n\n- `{{user.name|our team}}` — full name\n- `{{user.first_name|fallback}}` / `{{user.last_name|fallback}}`\n- `{{user.email|fallback}}`\n- `{{user.phone|fallback}}`\n- `{{user.extension|fallback}}`\n\n### Date\n\n- `{{date.today}}` — locale-friendly like \"Saturday, November 8\"\n- `{{date.tomorrow}}` — same, next day\n- Respects the agent's timezone if set (Working Hours tab)\n\n## Worked examples\n\n**Fixed-mode trigger message, tag-added event:**\n\n```\nHi {{contact.first_name|there}}, thanks for reaching out about\n{{custom.service_interest|our services}}. I'm {{agent.name|from the\nteam}}. Quick question — what's got you looking right now?\n```\n\n**Follow-up step, \"schedule a chat\":**\n\n```\nHey {{contact.first_name|there}}, looping back —\n{{user.name|our team}} has some availability\n{{date.tomorrow}}. Want me to lock in a time?\n```\n\n**Voice call opener:**\n\n```\nHi {{contact.first_name|there}}, this is {{agent.name|calling from}}\nabout your inquiry. Got a few minutes?\n```\n\n## The Insert-value picker\n\nEvery merge-aware textarea has a `{{…}} Insert value` button in the\ntop-right corner. Click it to get a grouped, searchable list of every\ntoken available — built-ins, your CRM custom fields (auto-fetched),\nand a link to this reference page. Typing into the search box filters\nlive; Enter inserts the top match at the cursor.\n\n## How it works at send time\n\nWhen a pre-written message is about to send, we:\n\n1. Load the contact record (name, fields, tags)\n2. Hydrate contact custom fields (match `fieldKey` to your tokens)\n3. Resolve the assigned user if any `{{user.*}}` tokens are used\n4. Substitute every `{{token}}` in the template\n5. Send the result\n\nIf any step fails (e.g. GHL scope missing, contact deleted), the\naffected tokens fall back to their `|fallback` value or render as\nempty — the message still sends. No half-rendered templates.\n\n## Common mistakes\n\n- **Using tokens in AI instructions** — the agent already has the\n  contact; writing `{{contact.first_name}}` in the system prompt is\n  redundant and often gets copied into the reply literally.\n- **Forgetting fallbacks** — `\"Hi {{contact.first_name}},\"` on an\n  anonymous contact renders as `\"Hi ,\"` which looks broken.\n  `\"Hi {{contact.first_name|there}},\"` is the fix.\n- **Assuming `{{user.*}}` works without the scope** — if you added\n  these tokens and see them coming back blank, GHL needs\n  reconnecting with the `users.readonly` scope.\n- **Using `{{custom.*}}` for opportunity data** — opportunity-level\n  fields (vehicle color, deal stage, etc.) aren't token-resolvable.\n  They're visible to [Advanced agents](/help/a/simple-vs-advanced-agents)\n  but the LLM references them in its own reply; you don't template them.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/merge-fields","publishedAt":"2026-04-27T22:57:22.791Z","updatedAt":"2026-06-26T03:30:00.275Z"},{"slug":"build-with-ai-wizard","title":"Build with AI: spin up an agent in 3 minutes by describing it","summary":"Skip the templates and the form-filling. Describe what you want the agent to do and we generate the system prompt, rules, qualifying questions, and tool selections for you.","body":"Setting up a new agent has historically meant filling forms across a\ndozen tabs — system prompt, behaviour rules, qualifying questions, tool\nselections, persona settings. **Build with AI** collapses that into a\n3-minute conversation.\n\nOpen it from **Agents → + New agent → ✨ Build with AI** (or directly at\n`/agents/new/wizard`).\n\n## How the conversation works\n\nYou start by describing what the agent should do, in plain English:\n\n> \"I want an agent that books demos for our SaaS product. It should\n> qualify leads on company size and budget before booking.\"\n\nThe wizard asks at most five clarifying questions, one at a time, on\ntopics like:\n\n- Tone and persona\n- Specific behaviors or rules\n- What outcome counts as a win\n- Anything the agent should never do\n\nWhen it has enough, it proposes a complete configuration:\n\n- **Name** — short, human-readable\n- **System prompt** — the agent's identity and job description\n- **Behavior rules** — bullet-list dos and don'ts\n- **Tools** — a sensible subset of available tools\n- **Detection rules** (optional) — \"if X then tag/note/workflow\"\n- **Qualifying questions** (optional) — questions woven into the\n  conversation with capture fields\n- **Persona tone** — sets the formality slider\n\nYou see the full proposal in a card with collapsible sections. Click\n**✓ Create this agent** to mint it, or **Tweak it** to adjust.\n\n## When to use the wizard vs templates\n\n**Wizard is better for:**\n\n- New users who don't know what tools or rules they need\n- Specific verticals where templates are too generic (\"HVAC technician\n  scheduling assistant\", \"real estate buyer qualifier\")\n- Quick prototyping — get something live and iterate\n\n**Templates are better for:**\n\n- Standard sales / support / scheduling flows where the template fits\n  cleanly\n- When you want a known starting point to customize manually\n- Replicating an existing agent's setup\n\nAfter creation, you land on the agent's settings tab and can edit\nanything — channels, persona details, additional rules, tools. The\nwizard creates a real agent, not a placeholder.\n\n## Pro tips\n\n- **Be specific about the win.** \"Book a demo with sales\" is better\n  than \"qualify leads\". The wizard uses this to pick tools and shape\n  the prompt.\n- **Mention your industry.** \"We sell HVAC services to homeowners\" gives\n  the wizard much better defaults than \"we sell things\".\n- **Mention what NOT to do.** \"Never quote prices, never promise refunds,\n  never mention competitors\" become explicit behavior rules.\n- **Skip what you don't care about.** If the wizard asks about persona\n  tone and you don't have a preference, say so — defaults are fine.\n\n## After creation\n\nThe new agent is live but not deployed. You'll still need to:\n\n1. Connect it to a channel under the **Channels** tab\n2. Activate it (top-right toggle on the agent page)\n3. Optionally fine-tune anything the wizard generated\n\nThe whole flow — describe → review → create → channel → activate —\nis usually under 10 minutes for a fresh agent.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/build-with-ai-wizard","publishedAt":"2026-04-29T10:27:46.407Z","updatedAt":"2026-06-26T03:29:52.877Z"},{"slug":"rules-vs-listening","title":"Rules vs Listening: what goes where","summary":"Rules write a known value to a known field. Listening takes free-text notes. Learn when to use each.","body":"Rules and Listening do superficially similar things — both detect\nsomething the contact said and act on it — but they serve different jobs.\nKnowing which to reach for saves you from forcing square pegs into round\nholes.\n\n## Rules: you know *what* you want and *where* to put it\n\nThe agent is a matching engine. You've already decided the field and the value.\n\n**Example**\n\n- Contact says: *\"I'm out of town this week\"*\n- Rule fires: set `custom.out_of_town` = `Yes`\n- The rule definition knows:\n  - The field (`custom.out_of_town`)\n  - The value (`Yes`)\n  - Which phrases count as a match (examples)\n\n**Data lives in**: your CRM (GHL contact field). Visible to anyone who\nopens the contact in GHL.\n\n**You author this when**: you have a structured field you want populated.\nThe value is predictable — it's going to be `Yes`, `Buyer`, `Tier 3`, etc.\n\nSee the full [Rules guide](/help/a/rules).\n\n## Listening: you know *what kind of thing* to remember\n\nThe agent is a note-taker. You've named a category of interest. The agent\nwrites the content in its own words.\n\n**Example**\n\n- Contact says: *\"My mum is sick, I've been a bit distracted\"*\n- Listening rule fires: category `Family context`\n- The agent writes a note: *\"Mother is unwell — contact is distracted this week\"*\n- The rule definition only knows:\n  - The category name (`Family context`)\n  - Roughly what fits (description + examples)\n  - It does NOT know in advance what the note will say\n\n**Data lives in**: the agent's private memory for that contact. NOT pushed\nto GHL. Shown back to the agent on future turns as \"what you already know\nabout this contact\" so it behaves like a human rep who remembers.\n\n**You author this when**: the valuable info is unpredictable and\ncontextual — family events, hobbies, objections, quirks, running jokes.\n\nSee the full [Listening guide](/help/a/listening).\n\n## Side-by-side\n\n| | **Rules** | **Listening** |\n|---|---|---|\n| User pre-defines the output? | Yes — field + value | No — agent writes content |\n| Where info lands | CRM contact field | Agent's private memory |\n| Visible in GHL? | Yes | No |\n| Shape | Structured | Free-text note |\n| Classic trigger | *\"I'm out of town\"* | *\"My mum is sick\"* |\n\n## Rough heuristic\n\n- If the value belongs on a **form** you'd ask someone to fill in → **Rules**\n- If the value belongs in a **sticky note** a sales rep would stick to the\n  contact's record → **Listening**\n\n## Why both exist\n\nRules can't handle \"mum is sick\" cleanly — you'd need a custom field called\n`family_situation` with a value like `Parent illness`, and you'd be trying\nto classify real human detail into a fixed taxonomy.\n\nListening can't handle \"out of town\" — you want `custom.out_of_town = Yes`\nspecifically so your automations, tags, and workflows can trigger off that\nexact boolean. Free-text in a memory note can't drive a workflow.\n\nUse both.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/rules-vs-listening","publishedAt":"2026-04-20T13:51:52.090Z","updatedAt":"2026-06-26T03:30:11.726Z"},{"slug":"inbox-assignment-routing","title":"Assign chats to teammates and auto-route widget conversations","summary":"Operators own conversations like in Intercom — manual claim, round-robin, or lightest-load auto-routing, with availability presence.","body":"Widget chats no longer just sit in a shared queue. Each conversation\ncan have a single **assigned operator** — set automatically when the AI\nhands off, when a teammate replies, or manually from the inbox.\n\n## What's new\n\n- **Assignee on every chat.** Visible on every inbox row and in the\n  conversation header.\n- **Inbox filters: Assigned to me / Unassigned / Everyone.** Operators\n  see only their work without scrolling past everyone else's.\n- **Available / Away presence.** Toggle from the inbox header. Auto-\n  routing skips \"away\" teammates so chats land with someone who's\n  actually online.\n- **Per-widget routing modes.** Configure how a specific widget assigns\n  chats: Manual (sit in queue), Round-robin (cycle through teammates),\n  or Lightest-load (whoever has the fewest open chats).\n- **Personal \"assigned to you\" notification.** New event in the\n  notifications panel — fires only on the assignee, not the whole team.\n\n## Three routing modes\n\nPick one per widget under **Widgets → \\[your widget\\] → Routing →\nOperator routing**. They only kick in when a chat needs a human (AI\nhandover or manual takeover) — the AI handles things normally before\nthat.\n\n**Manual** — chats stay in the unassigned queue until someone claims\nthem from the inbox. Best when one person is on duty at a time, or\nwhen you want full discretion.\n\n**Round-robin** — cycles through eligible *available* teammates in\ndeterministic order, using a stored cursor so the next chat goes to\nthe next person. Perfect for fair distribution across a team.\n\n**Lightest load** — picks the available teammate with the fewest open\nchats (status: active or handed_off). Smooths things out when one\noperator gets buried.\n\nFor round-robin and lightest-load, you can pin the **eligible\nteammates** — leave all unchecked to include everyone in the workspace,\nor check specific people for a sub-team.\n\n## Manual assignment\n\nClick the assignee chip in the conversation header to:\n\n- **Claim this chat** (one-click for \"I'm taking this\")\n- **Pick a teammate** from the dropdown — anyone in the workspace,\n  even teammates marked away (manual override)\n- **Unassign** to drop it back into the queue\n\nAssignment changes broadcast in real-time, so every open inbox tab\nupdates the moment someone claims or hands off.\n\n## Self-claim by replying\n\nIf you reply to an unassigned chat from the operator inbox, you\nautomatically become the assignee. Mirrors the Intercom convention —\nwhoever picks up the thread becomes the de-facto owner unless someone\nreassigns.\n\n## Available / Away\n\nThe toggle in the inbox header (top-right) sets your availability.\n**Available** means round-robin and lightest-load can route chats to\nyou. **Away** keeps you in the workspace but auto-routing skips you.\n\nToggle to Away when you're stepping out for lunch, in a meeting, or\njust don't want to be auto-assigned. Manual assignments still work\neither way — a teammate can still pick you specifically.\n\n## Notifications\n\nThe new **`widget.conversation_assigned`** event fires when you get\nassigned. By default it sends:\n\n- A web push to your browser\n- An email with a deep link to the chat\n\nManage it under **Settings → Notifications**. The event is *personal* —\nit only goes to the assignee, not the whole workspace, so you don't\nspam Slack on every assignment.\n\n## Common patterns\n\n**Solo operator** — set routing to Manual, leave yourself Available.\nYou see every new chat in the Unassigned queue and pick what to claim.\n\n**Small team, even split** — Round-robin across all eligible teammates.\nToggle yourself Away when you step out and the rotation skips you.\n\n**Tiered support** — Lightest-load mode, and pin only your tier-1\noperators as eligible. Tier-2/3 teammates only get chats by manual\nhand-off from tier-1.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/inbox-assignment-routing","publishedAt":"2026-04-29T10:27:46.780Z","updatedAt":"2026-06-26T03:29:56.901Z"},{"slug":"rules","title":"Rules: IF the contact says X, THEN do Y","summary":"Passive detection rules that run CRM actions — update fields, add tags, enroll in workflows, change opportunities, mark DND — based on what the contact says.","body":"Rules let you teach the agent to detect things in conversation and take\nautomatic action. The agent evaluates every inbound message against every\nactive rule.\n\n## Anatomy of a rule\n\nEach rule has four parts:\n\n1. **Name** — a short label so you can find it later (e.g. \"Out of town\")\n2. **When the contact…** — a plain-English description of the condition\n3. **Example phrases** — real phrases from your audience that should match\n4. **Then…** — the action that fires when the rule matches\n\n## Actions (the THEN)\n\nThe action picker covers every CRM action the agent can take based on\nconversation. Each one has its own parameter panel below the picker:\n\n- **Update contact field** — write a value to a standard or custom field.\n  Gets the \"keep first / always update\" toggle.\n- **Add tag(s) to contact** — apply one or more tags\n- **Remove tag(s) from contact** — strip tags\n- **Enrol contact in workflow(s)** — add to one or more published GHL\n  workflows (multi-select, same picker as the Tools tab)\n- **Remove contact from workflow(s)** — opposite\n- **Change opportunity status** — won / lost / abandoned / open\n- **Set opportunity value** — update the monetary value\n- **Mark contact as Do Not Disturb** — block the current conversation\n  channel, or pick a specific one\n\n## Example: update a field\n\n| Field | Value |\n|---|---|\n| Name | Out of Town |\n| When the contact… | indicates they are out of town, traveling, away, or otherwise unreachable |\n| Example phrases | `im out of town`, `im away sorry`, `back next week` |\n| Then | Update field `custom.out_of_town` → `Yes`, keep first |\n\n## Example: enrol in a workflow\n\n| Field | Value |\n|---|---|\n| Name | Interested in Service X |\n| When the contact… | asks about Service X pricing, shows interest in booking Service X |\n| Example phrases | `how much for Service X`, `can I book Service X`, `what's your Service X package` |\n| Then | Enrol in workflow: \"Service X nurture\" |\n\n## How the agent matches\n\nThe condition is evaluated **semantically**, not by keyword match. It\nhandles paraphrases, typos, and indirect answers. The example phrases are\nillustrative, not exhaustive — give 3–5 good ones and the agent generalises.\n\n## Tools auto-enable\n\nWhen you author a rule with an action (e.g. enrol in workflow), the\nunderlying tool (`add_to_workflow`) is enabled on the agent\nautomatically — you don't need to go to the Tools tab and toggle it\nseparately. Authoring the rule is consent.\n\n## Overwrite semantics (update_contact_field only)\n\nTwo modes when the action is \"Update contact field\":\n\n- **Keep first** (default) — only set the field if it's currently empty.\n  Good for \"first answer wins\" signals like `buy_or_rent = Buyer`.\n- **Always update** — overwrite every time the rule fires. Good for state\n  that changes (out-of-town, next_available_date).\n\n## When to use Rules vs [Listening](/help/a/listening)\n\n- **Rules** = structured CRM action. You know what should happen.\n- **Listening** = free-text note to agent memory. Info is too variable for\n  a fixed field.\n\nThe full comparison lives in [Rules vs Listening](/help/a/rules-vs-listening).\n\n## Common patterns to build first\n\n- Out-of-town → update `out_of_town` field\n- Interested in Service X → enrol in \"Service X nurture\" workflow\n- Asks to unsubscribe / stop → mark DND on channel + remove from nurture workflow\n- Budget confirmed ≥ $N → set opportunity value\n- \"No longer interested\" → mark opportunity as Lost + add `cold` tag","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/rules","publishedAt":"2026-04-20T13:51:52.469Z","updatedAt":"2026-06-26T03:30:02.305Z"},{"slug":"knowledge-collections","title":"Knowledge Collections","summary":"Build named bundles of FAQs, files, web pages, Notion docs, YouTube transcripts, and live data sources. Agents pick which collections to use — multi-select, stacked, edit once.","body":"Knowledge lives in **Collections** — named, reusable bundles of\neverything an agent needs to know about a topic. A collection holds\nwritten notes, FAQs, uploaded files, crawled web pages, Notion docs,\nYouTube transcripts, *and* live data sources (Google Sheets, Airtable,\nREST endpoints), all in one place. Agents don't own knowledge directly\nanymore — they connect to one or more collections, and inherit\neverything inside.\n\n## The shape of it\n\n- **Collections live at the workspace level.** Open the **Knowledge**\n  tab in the left nav. Every collection in the workspace shows as a\n  card with its icon, item count, data-source count, and how many\n  agents it's connected to.\n- **Items inside a collection** are mixed-type. A single collection\n  can hold a written FAQ, a PDF you uploaded, three crawled pages from\n  your help docs, and a Google Sheets data source — side by side. The\n  agent gets the static items as context in its prompt, and the data\n  sources as live-lookup tools.\n- **Agents subscribe.** Each agent's **Knowledge** sub-page is a\n  checklist of every collection in the workspace. Tick the ones the\n  agent should use. Save. Done.\n\n## Building a collection\n\n1. Go to **Knowledge** in the left nav and click **+ New collection**.\n2. Give it a name, an icon, and an accent colour. (e.g. \"Refunds &\n   returns\" 🛒, \"Product specs\" 📦, \"Brand voice\" 💼.)\n3. Open the collection. You'll see three tabs:\n\n### Items tab\nThe \"things the agent should read\" — static knowledge pulled into the\nsystem prompt. Six ways to add an item:\n\n- **Write** — a manual entry. Title + body.\n- **Q&A** — paste in question/answer pairs; each becomes its own item\n  so the agent can match individually.\n- **Crawl URL** — paste a web URL; we fetch the page, strip\n  formatting, chunk long content, and store the text. Comes back fast\n  with a chunk count.\n- **Upload file** — PDF, TXT, or Markdown (max 5 MB). Long files chunk\n  automatically.\n- **Notion / YouTube** — coming back into the collection editor; for\n  now use **Write** to paste the text.\n\n### Data sources tab\nThe \"things the agent can look up live\" — credentials and config for\nGoogle Sheets, Airtable, or REST GET endpoints. Each data source\nbecomes a tool the agent can call mid-conversation:\n\n- **Google Sheet** — pulls rows by query.\n- **Airtable** — queries records with formula filters.\n- **REST GET** — hits any HTTP endpoint and returns the JSON.\n\nGive it a slug name (lowercase, e.g. `inventory`); the agent calls\nit by that name. Paste the credentials — they're stored encrypted.\n\n### Connected agents tab\nMulti-select checklist of every agent in the workspace. Tick the ones\nthat should use this collection. Save replaces the full set — anything\nyou uncheck gets disconnected.\n\n## Connecting from the agent side\n\nYou can also wire collections from an agent's perspective. On any\nagent, the **Knowledge** sub-page is now a picker — every workspace\ncollection appears with a checkbox. Tick the ones you want, hit Save.\nSame effect, different angle. Use whichever feels natural for the\nmoment.\n\n## Why this exists\n\nBefore Collections, knowledge and data sources lived in two unrelated\nplaces — and knowledge entries were locked to a single agent. Sharing\nthe same FAQ across three agents meant duplicating it three times,\nthen editing three copies whenever something changed.\n\nCollections fix all three:\n\n- **One bundle, many agents.** A \"Brand voice\" collection on every\n  customer-facing agent. Update once; every agent picks it up next\n  turn.\n- **Mixed types in one place.** The \"Product specs\" collection holds\n  the spec PDF, the FAQ pairs, and the live inventory Sheet. An agent\n  attached to it gets all three on the same connection.\n- **Build once, reuse anywhere.** When you spin up a new agent, you\n  don't rebuild knowledge — you tick the collections it needs and\n  start tuning behaviour instead.\n\n## Migration\n\nEverything from before — knowledge entries you'd written and data\nsources you'd configured — was automatically dropped into a default\n**General** collection in each workspace. Every agent that previously\nused those items was connected to General. Day-one prompt context is\nidentical to what it was before.\n\nTo reorganise, just create new collections and move items by\nrecreating them in the right place (each item belongs to exactly one\ncollection). Or rename **General** and split items into topic-specific\ncollections as you go.\n\n## A clean pattern\n\nFor workspaces with multiple agents on the same business, a\ncollection-per-topic layout works well:\n\n- **Brand voice** (one shared collection) → on every agent.\n- **Refunds & returns** → on support + voice agents.\n- **Product specs** (with the inventory Sheet inside) → on sales +\n  support + voice agents.\n- **Sales playbook** → on sales agent only.\n\nEach agent inherits exactly what it needs by checking 2–4 collections,\nand any change you make to a collection ripples to every agent on it.\n\n## Things to know\n\n- **Delete a collection** to remove it everywhere. Every connected\n  agent loses access; the items inside are deleted too.\n- **Delete an item inside a collection** to remove just that item.\n  Other items in the collection stay; agents keep using the\n  collection.\n- **Disconnect an agent** by un-ticking the collection in the agent's\n  Knowledge picker (or in the collection's Connected agents tab). The\n  collection survives untouched.\n- **Data sources only surface as tools** when an agent connects to the\n  collection that holds them. So you control which agents can call\n  which data sources by where you put them.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/knowledge-collections","publishedAt":"2026-04-29T10:27:47.152Z","updatedAt":"2026-06-26T03:30:14.644Z"},{"slug":"listening","title":"Listening: categories the agent remembers","summary":"Teach the agent to keep private notes about contacts without asking, and reference them in future chats.","body":"Listening lets you name categories of context the agent watches for\n*without asking*. When the contact volunteers something that fits, the\nagent writes a short note in its own words to the contact's memory.\n\n## How it's different from Rules\n\nRules write a known value to a known field. Listening captures free-text\ncontext the user couldn't have anticipated. Read\n[Rules vs Listening](/help/a/rules-vs-listening) for the full comparison.\n\n## Anatomy of a listening category\n\n1. **Category name** — a short label (e.g. \"Family context\", \"Pain points\")\n2. **Listen for** — a plain-English description of the kind of thing this\n   category covers\n3. **Example phrases** — real phrases to help the agent generalise\n\nThat's it. No field, no value — the agent decides what to write.\n\n## Example\n\n| Field | Value |\n|---|---|\n| Category name | Family context |\n| Listen for | family members, health issues, life events |\n| Example phrases | `my mum is sick`, `just got engaged`, `dealing with a lot at home` |\n\nWhen a contact says *\"my mum had a heart attack last week\"*, the agent\nwrites a note: *\"Mother recently had a heart attack — contact dealing with\nfamily health issue.\"*\n\n## What happens to the note\n\nIt's stored in the agent's private memory for that contact. On every\nfuture conversation with this contact (on any channel), the agent sees:\n\n```\n## What You Already Know About This Contact\n\n- Family context: Mother recently had a heart attack — contact dealing with family health issue.\n- Pain points: Budget is tight; mentioned avoiding anything above $500.\n```\n\nThe agent then uses it naturally — not by quoting it, but by softening\ntone, remembering to check in, avoiding tone-deaf recommendations.\n\n## Where the note is NOT\n\nIt's **not** pushed to GHL. It's not on the contact record. It's not in a\nfield any automation can read. This is deliberate — this info is the\nagent's private notebook, not structured CRM data.\n\n## Good categories\n\n- **Family context** — spouses, kids, parents, life events\n- **Pain points** — frustrations with current solution, specific objections\n- **Preferences** — morning vs evening, phone vs text, direct vs friendly\n- **Deal context** — timing pressure, stakeholders, competing options\n- **Personal touchpoints** — pets, hobbies, sports teams, holidays\n\n## Less-good categories\n\n- Anything you'd want a workflow to fire on → use Rules + a field\n- Anything that belongs on a form → use Qualifying questions","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/listening","publishedAt":"2026-04-20T13:51:52.849Z","updatedAt":"2026-06-26T03:30:06.482Z"},{"slug":"brands-whitelabel","title":"Brands — run a whitelabel agency from one workspace","summary":"Tag widgets and knowledge collections to a brand. Inbox filters, transcript exports, and per-client knowledge stay clean — even when one team handles many brands.","body":"If you represent multiple clients (whitelabel agency, holdco\nsupport team, MSP), you need one operator queue, one set of agents,\nbut cleanly separated **conversations, knowledge, and reporting** per\nbrand. Brands let you tag widgets and collections so the right things\nfilter, group, and export under each client identity — without\nspinning up a workspace per brand.\n\n## What a brand is\n\nA brand is a small workspace-level entity:\n\n- **Name** — the human label (\"Acme Corp\", \"Beta Co\").\n- **Slug** — URL-safe identifier used in transcript exports and the\n  brand-scoped inbox URL.\n- **Logo + accent color** — for visual identification on the operator\n  inbox so a glance tells you which brand a chat is for.\n- **Description** — optional notes for your team.\n\nIt's optional. Workspaces that aren't running a multi-brand setup\nignore the whole concept; the inbox doesn't show brand controls when\nthere are no brands.\n\n## Tag widgets to a brand\n\nEach widget has a **Brand** dropdown in its Routing section. Picking\na brand flows through to:\n\n- **Inbox row chip** — every conversation from that widget shows the\n  brand chip with logo and accent color.\n- **Inbox brand filter** — operators can scope to one brand at a time.\n- **Transcript export** — the per-brand JSON / text export pulls\n  every conversation on every widget tagged to that brand.\n\nUntagged widgets keep working — they just show up in \"Untagged\" in\nthe inbox brand filter.\n\n## Tag collections to a brand\n\nWhen you create a Knowledge Collection, you can pick a brand:\n\n- **Brand-scoped** — only relevant to that client. \"Acme refund\n  policy,\" \"Beta shipping windows.\"\n- **Shared across brands** (no brand picked) — useful for things that\n  are universal in your team's voice or method, regardless of which\n  brand you're representing.\n\nConnect collections to agents the same way as before — agents pick\nwhich collections to use. A single agent can handle multiple brands\nby being attached to brand-scoped collections for each one.\n\n## The inbox\n\nOpen **Inbox** in the left nav. With brands defined, a new **Brand**\nfilter row appears (above the status tabs):\n\n- **All** (default) — every conversation, brand or not.\n- **Untagged** — conversations on widgets that aren't tagged to any\n  brand.\n- **One row per brand** — click to scope.\n\nWhen you scope to a specific brand, an **Export** button appears in\nthe top-right of the brand filter row. Click it to download every\nconversation tagged to that brand as JSON.\n\n## Transcript exports\n\nTwo formats, both via the brand detail or inbox:\n\n`GET /api/workspaces/:wid/brands/:bid/transcripts/export?format=json`\n- Full structured export — every conversation, every message, CSAT\n  ratings, assignment, timestamps. Filename: `<brand-slug>-transcripts-<date>.json`.\n\n`?format=text`\n- Human-readable plain-text concatenation. Useful for skimming or\n  feeding into a QA review.\n\nOptional query params:\n- `from=YYYY-MM-DD` and `to=YYYY-MM-DD` — date range.\n- `status=ended` (or `active` / `handed_off`) — narrow to one status.\n\nCapped at 1,000 conversations per export — chunk longer archives via\nthe date range.\n\n## A clean pattern\n\nFor an agency running 5 brands:\n\n1. Create 5 brands under **Brands** in the left nav.\n2. For each brand, create one widget tagged to it (chat or\n   click-to-call). Different colours, logos, hostnames in\n   \"Allowed domains.\"\n3. Create one **Brand-scoped collection** per brand for FAQs, refund\n   terms, and any client-specific docs.\n4. Create one **shared collection** per skill (Brand voice, support\n   playbook) — no brand tag, used by every agent.\n5. One agent per brand: attach the brand's collections + the shared\n   ones. The agent runs with the right knowledge mix automatically.\n6. Operators sit in **Inbox** and either work the All view or scope\n   to a brand. The brand chip on each conversation makes context\n   obvious without clicking in.\n\nWhen clients ask for a transcript audit (\"show me everything that\nwent through Acme last quarter\"), open Brands, click the brand,\nand hit Export.\n\n## Things to know\n\n- **Deleting a brand doesn't delete widgets or collections.** They\n  become \"untagged\" and stay in the workspace.\n- **Brands are workspace-scoped.** If you need cross-workspace brand\n  separation, you still need separate workspaces.\n- **The brand chip is purely visual** — the brand identity doesn't\n  alter the agent's behaviour. To change voice or knowledge per\n  brand, swap which collections each agent uses.\n","category":{"name":"What's new","slug":"releases"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/brands-whitelabel","publishedAt":"2026-06-12T03:01:08.707Z","updatedAt":"2026-06-26T03:29:58.129Z"},{"slug":"tools","title":"Tools: what the agent can do","summary":"The verbs available to the agent — send messages, book appointments, tag contacts, enroll in workflows, hand off to humans.","body":"The **Tools** tab is where you pick which actions the agent is allowed to\ntake. Each tool is a verb the agent can call during a conversation.\n\n## Categories\n\n**Messaging**\n- `send_reply` — reply on the current channel\n- `send_email` — send an email (separate from chat reply)\n- `send_sms` — legacy SMS (most agents use `send_reply` instead)\n\n**Contacts**\n- `get_contact_details` — look up the contact\n- `update_contact_tags` — add tags\n- `remove_contact_tags` — remove tags\n- `update_contact_field` — set a standard or custom field\n- `find_contact_by_email_or_phone` — dedupe check\n- `upsert_contact` — create or update\n- `create_task` — assign a follow-up task to a team member\n- `add_contact_note` — log internal context\n\n**Calendar / Booking**\n- `get_available_slots` — check availability\n- `book_appointment` — commit a booking\n- `cancel_appointment` / `reschedule_appointment`\n- `create_appointment_note` — log context onto the appointment\n\n**Automation**\n- `add_to_workflow` / `remove_from_workflow` — GHL workflow enrollment\n- `cancel_scheduled_message` — cancel a queued SMS/email\n\n**Pipeline**\n- `get_opportunities` / `upsert_opportunity`\n- `move_opportunity_stage`\n- `mark_opportunity_won` / `mark_opportunity_lost`\n- `list_pipelines`\n\n**Intelligence / flow**\n- `transfer_to_human` — [hand off](/help/a/human-handover-notifications)\n- `schedule_followup` — queue a future message\n- `score_lead`, `detect_sentiment`\n- `save_qualifying_answer` — fires automatically as [qualifying questions](/help/a/qualifying) get answered\n\n## Workflow tools\n\nEnable `add_to_workflow` / `remove_from_workflow` to allow the agent to\nenrol contacts in (or remove them from) GHL workflows. The specific\nworkflow to use is picked per-rule on the [Rules tab](/help/a/rules) —\nthat's where you say \"when the contact asks about Service X, enrol them\nin the Service X nurture\". The toggle here just grants the capability.\n\nThe same applies to any rule-driven action: `update_contact_tags`,\n`opportunity_status`, `dnd_channel`, etc. Rules author the specific\naction; the Tools tab is consent that the tool exists.\n\n## Calendar setup\n\nTurning on `get_available_slots` or `book_appointment` auto-enables the\nfull booking tool set (cancel, reschedule, get_calendar_events, create_appointment_note).\nYou'll also need to pick a **Connected Calendar** in the panel that\nappears — without it, booking tools fail silently.\n\nUse the **Test calendar connection** button to verify: it runs a series of\nchecks (token valid, scope present, calendar readable, team-member\nassignment working) and shows you exactly what's wrong if anything is.\n\n## Design principle\n\n**Only enable tools the agent should actually use.** Every enabled tool\nadds to the agent's schema, which slightly dilutes focus. An agent with 8\nfocused tools will outperform an agent with 25 generic ones every time.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/tools","publishedAt":"2026-04-20T13:51:53.230Z","updatedAt":"2026-06-26T03:30:02.853Z"},{"slug":"qualifying","title":"Qualifying questions: what to ask, what to do with the answer","summary":"Scripted questions the agent asks to fill contact fields, plus conditional actions when specific answers land.","body":"Qualifying questions are the agent's scripted intake. Each one asks for a\npiece of information, saves the answer to a contact field, and can\noptionally fire an action based on how the contact responds.\n\n## The question\n\nFour answer types:\n- **Text** — free-form\n- **Yes / No** — boolean\n- **Number** — numeric\n- **Multiple Choice** — pick from options you define\n\nYou can save the answer directly to a contact field (standard or custom).\nThe **Keep first / Always update** toggle controls overwrite semantics —\nsame as [Rules](/help/a/rules).\n\n## Asking style\n\nTwo modes, set per agent:\n\n- **Strict** — the agent MUST ask every required question before anything\n  else. Good for tight funnels where you need data upfront.\n- **Natural** — the agent weaves questions into the conversation as\n  opportunities arise. Good for consultative sales.\n\n## Conditional Action (the fun part)\n\nEach question can trigger an action based on the answer. The condition\noperators:\n\n- **is anything** — always trigger\n- **is yes** / **is no** — for yes/no questions\n- **contains** / **equals** — for text answers\n- **is greater than** / **less than** — for numeric answers\n- **is any of…** — for multi-choice, pick which specific options trigger\n\nAvailable actions:\n\n- **Continue conversation** — proceed as normal\n- **Tag contact with** — add a tag\n- **Move to pipeline stage** — progress the opportunity\n- **Proceed to book appointment** — the agent starts the booking flow\n- **Stop & hand off to human** — [fires the handover](/help/a/human-handover-notifications)\n- **Add contact to workflow(s)** — enroll in GHL workflows (multi-select)\n- **Remove contact from workflow(s)**\n- **Change opportunity status** — won / lost / abandoned / open\n- **Set opportunity value** — update monetary value\n- **Mark contact DND on this channel** — block this channel\n\n## Example\n\n| | |\n|---|---|\n| Question | \"Are you looking to buy or sell?\" |\n| Answer Type | Multiple Choice |\n| Options | Buy, Sell, Both, Just browsing |\n| Save to field | `custom.intent` |\n| If answer is any of | `Just browsing` |\n| Then | Mark contact DND on this channel |\n\n## Tips\n\n- **Ask one question at a time.** The agent knows not to stack them, but\n  your prompts should still be scoped to one ask.\n- **Pre-populate when you can.** If the answer is already on the contact\n  record, the agent skips asking.\n- **Don't ask 20 questions.** Every required question is a gate the\n  contact has to pass. 3–5 really useful ones beats 12 mediocre ones.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/qualifying","publishedAt":"2026-04-20T13:51:53.610Z","updatedAt":"2026-06-26T03:30:01.282Z"},{"slug":"persona","title":"Persona: how the agent sounds","summary":"Voice, tone, response length, emoji use, language, typing behaviour. The personality layer.","body":"The **Persona** tab shapes *how* the agent communicates — not *what* it\ndoes. Same system prompt + different persona = wildly different feel.\n\n## Fields\n\n**Agent Persona Name** — the name the agent uses when introducing itself.\nLeave blank if you don't want it to use a specific name.\n\n**Response Length**\n- **Brief** — one sentence max. Good for SMS.\n- **Moderate** — 1–3 sentences. Good default for most chat/messaging.\n- **Detailed** — full context when needed. Good for email or complex support.\n\n**Formality Level**\n- **Casual** — contractions, friendly, relaxed\n- **Neutral** — professional but approachable\n- **Formal** — strict professional tone\n\n**Use Emojis** — allows occasional (not constant) emoji use.\n\n**Simulate Typos** — adds subtle typos to humanise SMS-style channels. Off\nby default; turn on if you want the agent to feel less robotic.\n\n**Typing Delay** — when enabled, the agent waits a random delay (within\nyour min/max) before sending each message, simulating human typing speed.\nGood for chat widgets; overkill for email.\n\n**Languages** — which languages the agent can respond in. The agent\ndetects the inbound language and matches.\n\n**Never Say List** — words or phrases the agent must not use. Great for\ncompliance: \"guarantee\", \"cure\", \"best\", \"free\" — whatever trips your\nlegal or marketing style guide.\n\n## How personas compose with the system prompt\n\nThe system prompt says WHAT the agent does. The persona says HOW. They're\nindependent — you can swap one without touching the other.\n\nIf you're running multiple agents across channels, persona is usually\nwhere they differ most:\n- SMS agent → Brief + Casual + Emojis OFF\n- Live chat agent → Moderate + Casual + Emojis ON + Typing delay ON\n- Email agent → Detailed + Neutral + Emojis OFF\n\n## Tips\n\n- **Don't stack \"Brief + Formal + No emoji\" on a chat widget.** That reads\n  as cold. Match the persona to the channel's native register.\n- **Never Say List > Behavioural Instructions for single phrases.** Easier\n  to maintain and the agent respects it more reliably.\n- Use the Playground to audition persona changes before shipping.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/persona","publishedAt":"2026-04-20T13:51:53.991Z","updatedAt":"2026-06-26T03:30:03.371Z"},{"slug":"objectives-wins","title":"Objectives: what a \"win\" looks like","summary":"Define the outcomes that matter so the agent can push toward them — and so you can measure success.","body":"The **Objectives** tab (sometimes labelled \"Wins\") defines what success\nlooks like for this agent. It serves two purposes:\n\n1. **Shapes the agent** — the objectives are injected into the agent's\n   context so it naturally nudges toward them.\n2. **Measures the agent** — lets Voxility attribute wins to specific\n   conversations in Performance and Insights.\n\n## Anatomy of an objective\n\nEach one has:\n\n- **Name** — short label (e.g. \"Booked consultation\")\n- **Description** — what counts as a win\n- **Detection** — how the agent knows it happened (a tool call, a phrase, a\n  tag, an opportunity status change)\n\n## Example objectives\n\n- **Booked consultation** → fires when `book_appointment` is called\n- **Hot-lead qualified** → fires when `custom.lead_score > 7`\n- **Pricing question answered** → fires when the agent quoted pricing AND\n  the contact replied positively\n- **Referred to partner** → fires when specific tag is applied\n\n## How the agent uses them\n\nYour objectives are rendered into the system prompt as \"the wins you care\nabout\". The agent reads them on every turn and steers the conversation.\nIt's softer than a hard rule — the agent won't force a booking if it's\ninappropriate — but it measurably increases conversion for well-written\nobjectives.\n\n## Measuring\n\nObjectives are the scorecard the Insights, Performance, and Wins\ndashboards all use. Every objective achieved is logged with the\nconversation that produced it, so you can see:\n\n- Objectives per day / week\n- Conversion rate per agent\n- Which conversations achieved which wins\n\n## Tips\n\n- **2–5 objectives per agent.** More than that dilutes focus.\n- **Make them measurable.** \"Build rapport\" is fuzzy; \"collected email\n  address\" is concrete.\n- **Order matters.** The first objective listed is treated as the primary\n  goal — the agent optimises for it when two objectives conflict.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/objectives-wins","publishedAt":"2026-04-20T13:51:54.370Z","updatedAt":"2026-06-26T03:30:04.469Z"},{"slug":"stop-conditions","title":"Stop conditions: when the agent should stand down","summary":"Auto-pause on bookings, keywords, hostile sentiment, message counts. Tag needs-attention and trigger GHL workflows on the way out.","body":"Stop conditions define when the agent should pause itself on a specific\nconversation. Different from **transfer_to_human** (which the agent calls\nitself when stuck) — stop conditions are *your* rules for when the agent\nshould stop even if it thinks it's doing fine.\n\n## Why you'd want this\n\n- **Don't double-handle after booking.** Agent booked the meeting — stop\n  pinging the contact.\n- **Pause the moment the contact gets hostile.** Angry language, legal\n  threats, demands for refunds — flip the bot off before it makes things\n  worse.\n- **Human takes over after a specific keyword.** e.g. \"manager\" or\n  \"attorney\" — the contact has asked for a human, don't keep talking.\n- **Message limit.** After 15 turns, if no booking, escalate to a human\n  rep. Protects against runaway agent loops.\n- **Pipeline stage change.** Deal moved to \"negotiation\" — humans own it\n  from here.\n\n## Condition types\n\n- **Appointment booked** — fires when `book_appointment` succeeds\n- **Keyword** — fires when the inbound message contains any of your\n  keywords (comma-separated)\n- **Message count** — fires when the conversation hits N total messages\n- **Pipeline stage** — fires when `move_opportunity_stage` runs\n- **Hostile / angry sentiment** — fires when the inbound matches a\n  built-in hostile-language pattern (hate, lawyer, refund now, scam,\n  profanity, unacceptable, etc.) OR any extra keywords you supply.\n  Deliberately broad — false positives just show up on the review\n  queue, false negatives let angry contacts keep getting bot replies.\n\n## Actions when a condition fires\n\nEvery condition carries its own action config — you can mix and match:\n\n- **Pause agent** (default on) — stops all further replies until a\n  human resumes the conversation. Turn this OFF for a *flag-only*\n  rule that just raises awareness without interrupting the flow.\n- **Tag `needs-attention`** (default on) — the contact shows up on\n  the [Needs Attention review queue](/help/a/needs-attention-queue)\n  for a human to pick up. The tag is searchable in GHL if you want\n  custom segments built on top.\n- **Enrol in workflow** (optional) — GHL workflow ID. The contact is\n  added the moment the condition trips. Handy for \"hostile customer\n  recovery\" sequences that fire automatically.\n- **Remove from workflow** (optional) — GHL workflow ID. The contact\n  is pulled out. Handy for yanking someone out of a nurture drip the\n  moment they ask to cancel.\n\nWorkflow pickers only appear if your GHL connection includes the\n`workflows.readonly` scope. Reconnect from Integrations if the\npicker shows no options.\n\n## Flag-only (non-pausing) patterns\n\nYou don't have to stop the agent — you can just flag a contact. Common\npatterns:\n\n- **Sentiment, flag-only:** Keep replying, but tag every hostile\n  inbound `needs-attention` and enrol into a \"support escalation\"\n  workflow. The bot keeps the conversation warm while a human gets\n  looped in.\n- **Keyword \"refund\", flag-only:** Tag and enrol into a finance-team\n  workflow without pausing — the agent keeps going, finance gets\n  looped in async.\n\n## What happens end-to-end when a condition fires\n\n1. The condition's **actions** run (tag, enrol, remove — each\n   best-effort, one failure doesn't block the others)\n2. If **Pause agent** is on, the conversation state flips to PAUSED —\n   the agent won't reply to further inbounds on this thread\n3. A **needs_attention** notification fires on your configured channels\n   (Slack, Discord, email, SMS — see [human handover notifications](/help/a/human-handover-notifications))\n4. The conversation can be **resumed** manually from the Inbox\n   Needs-Attention queue once a human has picked it up\n\n## Pause vs Transfer\n\n- **Stop condition** → automatic pause based on your rule\n- **transfer_to_human** → the agent decides it's over its head and calls\n  the handover tool\n- **Fallback: transfer** → the agent hits a question it can't answer and\n  your fallback setting escalates it\n\nAll three fire the same [human-handover notifications](/help/a/human-handover-notifications)\nso whoever's on-call gets a deep link either way.\n\n## Tips\n\n- **Always add a SENTIMENT condition.** The built-in pattern catches\n  most hostile language; you can leave the extra-keywords field empty\n  for v1. Pair with a recovery workflow and you've got a safety net\n  that runs itself.\n- **Always set a message-count stop condition.** Catches runaway loops\n  cheaply. 20 is a reasonable default.\n- **Layer keyword + sentiment.** Sentiment catches emotional tone;\n  keyword catches specific phrases (\"speak to manager\") the agent\n  might miss. Belt and braces.\n- **Test with the Playground.** Fire the condition manually to make\n  sure your notification subscribers get pinged and your workflows\n  enrol as expected.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/stop-conditions","publishedAt":"2026-04-20T13:51:54.750Z","updatedAt":"2026-06-26T03:30:12.225Z"},{"slug":"triggers","title":"Triggers: start conversations, not just reply to them","summary":"Fire a first message when a contact hits a specific event — new contact, tag added, etc. Edit, test-fire, delay by days/hours/minutes.","body":"Triggers let the agent *start* conversations, not just respond to them.\nThey listen for events in your CRM and kick off an outbound message.\n\n## Event types\n\n- **New contact created** — someone just hit your CRM for the first time.\n  **Fires on EVERY new contact** — form submissions, imports, API calls,\n  manual adds, other workflows. The UI highlights this event in amber\n  with a ⚠️ banner because operators have lit up their entire pipeline\n  more than once by underestimating it. If you only want to fire for a\n  specific source (a form, a paid campaign), **use Tag added instead**\n  and tag contacts from your intended source.\n- **Tag added** — a specific tag got applied to a contact. Much safer\n  for targeted outbound — you control exactly which contacts get\n  messaged by controlling which ones get the tag.\n\nMore event types are on the roadmap (opportunity stage changed, form\nsubmitted, etc.) — flag what you need.\n\n## Tag picker\n\nWhen you pick the **Tag added** event, the tag filter field becomes a\nsearchable picker sourced from your GHL location's tags. Type to filter,\npick one from the dropdown, or type a new name and hit Enter / click\n\"Create\" to create it in GHL on the spot. Requires the\n`locations/tags.readonly` + `locations/tags.write` scopes on your\nGHL connection — reconnect from Integrations if the picker shows\n\"missing scope.\"\n\n## Channel\n\nEach trigger picks which channel the agent opens on — SMS, WhatsApp,\nEmail, etc. The channel must be enabled on the [Channels](/help/a/channels)\ntab or the message won't send.\n\n## Message modes\n\n**Fixed message** — a pre-written template. Supports [merge\nfields](/help/a/merge-fields) so you can personalise:\n\n```\nHi {{contact.first_name|there}}, thanks for reaching out about\n{{custom.service_interest|our services}}! {{user.first_name|I}} will\nbe in touch shortly.\n```\n\nGood for: consistent openers, compliance-sensitive industries, simple\nnurture sequences.\n\n**AI-generated message** — the agent generates the first message using\nthe system prompt + optional extra instructions:\n\n```\nGreet the new lead warmly, mention that you saw they filled out the form,\nand ask what they're looking for. Don't quote prices.\n```\n\nGood for: higher-value leads where a personalised open matters; scenarios\nwhere you want the agent to pull from knowledge + persona (especially\non [Advanced agents](/help/a/simple-vs-advanced-agents) where the LLM\nalso has the contact's opportunities in view).\n\n## Delay before sending\n\nThe delay picker is four separate fields — **days, hours, minutes,\nseconds** — so you can express human-friendly waits without doing\nmental math. `delaySeconds` is stored under the hood; the existing\ntrigger list renders the total back as something readable like\n`2d 4h` on the card.\n\nUseful for:\n- **Lead form follow-up** — wait 2 minutes so it feels human, not bot-fast\n- **Tag-added nurture** — wait 1 hour so humans have first dibs\n- **Overnight capture** — wait 8h so form submissions at 11pm don't\n  text at 11:02pm\n\nWorking hours still apply on top — if the scheduled send-time lands\noutside your window, it bumps to the next open slot.\n\n## Editing a trigger\n\nEvery trigger card has **Edit**, **Test fire**, and **Delete** buttons.\nClicking Edit loads the trigger's values into the same form you created\nit with — change the event, swap the channel, rewrite the message,\nadjust the delay — then **Save Changes**. Nothing else about the agent\nchanges; edits are atomic to that one trigger.\n\n## Test-firing a trigger\n\nThe **Test fire** button on each card opens a mini panel where you can\npaste a contact ID, phone, or email and fire the trigger against that\nspecific contact. The message actually sends — use a contact you own.\nThe test fire path skips the 60-second per-contact dedupe so you can\nre-fire repeatedly while QA'ing.\n\nUse this to verify:\n- Fixed-mode merge fields render the way you expect\n- AI mode produces a sensible opener\n- Tag filters actually match (test a contact with and without the tag)\n- Delay handling — test-fire triggers bypass working hours, so a\n  weekend test still fires\n\n## Working hours + triggers\n\nReal triggers respect [working hours](/help/a/working-hours) — if\nthe trigger fires outside your window, it's held until the window\nopens. Inbound replies ignore working hours; triggers are outbound\nand DO respect them. Test-fire is the exception — it fires now\nregardless.\n\n## GoHighLevel webhook subscription\n\nTriggers listen for webhook events from your connected GHL marketplace\napp. If Test Fire works but real-event triggers don't, the most common\ncause is that the marketplace app isn't subscribed to the matching\nevent. You need both `ContactCreate` AND `ContactTagUpdate` in the\nsubscribed events list.\n\n## Design tips\n\n- **One trigger per distinct outbound scenario.** Don't try to make one\n  trigger handle three different events.\n- **Prefer Tag added over New Contact Created.** Unless you really do\n  want to pitch *every* contact that lands in your CRM.\n- **Start fixed, upgrade to AI-generated.** Fixed openers are predictable\n  and easy to QA. Switch to AI mode once you trust the agent's voice.\n- **Watch for trigger storms.** If you mass-upload 5000 contacts with a\n  trigger tag, the agent will try to text all 5000. Stagger uploads or\n  add a [stop condition](/help/a/stop-conditions) for `do-not-contact`.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/triggers","publishedAt":"2026-04-20T13:51:55.374Z","updatedAt":"2026-06-26T03:30:06.006Z"},{"slug":"follow-ups","title":"Follow-ups: nudging quiet contacts","summary":"Multi-step automated nudges when a contact goes silent, says a keyword, or the agent decides it's time.","body":"Follow-up sequences keep a contact warm when the conversation has stalled.\nUnlike [Triggers](/help/a/triggers) (which *start* conversations),\nfollow-ups *continue* them.\n\n## Trigger types\n\n**No reply** — contact went silent. Fires after the delay on each step\nfrom the contact's last message.\n\n**Keyword detected** — contact said something that triggers the sequence.\n`follow up`, `call me back`, `not now` — classic lay-low signals.\n\n**Agent decides** — the agent itself calls the `schedule_followup` tool\nwhen it judges it's time. Gives the agent full discretion.\n\n**After every exchange** — starts a fresh sequence each time the contact\nmessages. Rare, but useful for aggressive re-engagement flows.\n\n## Sequence shape\n\nEach sequence is a list of **steps**. Each step has:\n\n- **Step number** — order\n- **Delay** — how long after the previous step (or after the trigger, for\n  step 1) to wait\n- **Message** — the text to send. Supports [merge\n  fields](/help/a/merge-fields).\n\nExample 3-step no-reply sequence:\n\n| Step | Delay | Message |\n|---|---|---|\n| 1 | 24 hrs | Hey {{contact.first_name|there}} — just checking back in. Still interested? |\n| 2 | 72 hrs | Following up once more {{contact.first_name|—}} want me to send more info, or shall I close the loop? |\n| 3 | 7 days | I'll stop the messages here. If the timing's better later, just reply. |\n\n## Working hours + follow-ups\n\nFollow-ups respect [working hours](/help/a/working-hours). If step 2 is\nscheduled for 3am, we push it to 9am (or whenever your window opens).\n\n## What stops a sequence\n\n- **Contact replies.** Any inbound cancels the remainder of the sequence —\n  you don't want to send step 3 after they've booked a meeting.\n- **Stop condition fires.** Agent paused → follow-ups paused.\n- **Contact marked DND.** No more outbound.\n- **Sequence finishes.** All steps sent.\n\n## Cancellation via AI\n\nThe agent can call `cancel_scheduled_message` if it decides a queued\nfollow-up no longer makes sense (e.g. the contact said \"please stop\nmessaging me\" but it doesn't quite match your sequence's stop keywords).\n\n## Tips\n\n- **Start with 2–3 steps.** Long sequences feel spammy.\n- **Escalate urgency gently.** Don't jump from \"hi\" to \"last chance\" on\n  step 2.\n- **Use merge fields.** A first-name + context line is much less\n  robotic-feeling than a generic \"Following up.\"\n- **Test from the Playground.** The sequence UI lets you \"fire now\" for\n  any step to verify copy before it goes out.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/follow-ups","publishedAt":"2026-04-20T13:51:55.759Z","updatedAt":"2026-06-26T03:30:06.996Z"},{"slug":"voice","title":"Voice: phone-call agents","summary":"Real-time voice agents that answer inbound calls, speak naturally, and book appointments.","body":"The **Voice** tab turns your agent into a phone-answering voice agent.\nInbound calls route to the phone number you provision, the agent answers\nin a voice you picked, and it can handle the full conversation — bookings\nand all.\n\n## Getting started\n\n1. **Provision a phone number.** Click **+ Get a number**, optionally with\n   an area code preference. We buy the number through Vapi and attach it\n   to this agent. US numbers only at the moment.\n2. **Pick a voice.** Browse 11labs voices, preview them, pick one. Common\n   picks: Sarah (friendly American female), Adam (neutral American male),\n   Rachel (clear, broadcaster feel).\n3. **Tune it.** Four sliders:\n   - **Speed** — 0.5x to 2.0x. Most voices feel natural at 1.0.\n   - **Stability** — higher = more consistent, lower = more expressive\n   - **Clarity + Similarity** — higher = closer to original voice\n   - **Style Exaggeration** — amplifies the voice's character\n4. **Write the opening + closing.** Supports [merge\n   fields](/help/a/merge-fields):\n   ```\n   Hi {{contact.first_name|there}}, thanks for calling. What can I help with?\n   ```\n5. **Enable voice.** Toggle the agent on.\n\n## How voice agents differ from chat agents\n\nSame brain, different instructions:\n\n- **Much shorter responses.** 1–3 sentences max — people don't listen to\n  monologues on the phone.\n- **No markdown, no lists.** Plain prose only.\n- **Natural speech patterns.** \"Uh-huh\", \"let me check that for you\",\n  brief acknowledgments.\n- **Separate tool set.** Some CRM tools work the same, some are\n  voice-specific (e.g. `send_sms_followup` sends an SMS after the call).\n\nWe inject voice-specific instructions into the system prompt automatically\n— you don't need to rewrite your prompt for voice.\n\n## Test calls\n\nUse **Start call** in the Test Call panel to dial your agent from the\nbrowser (mic permission required). Full transcript + volume indicator\nvisible during the call. Great for auditioning voice tuning changes.\n\n## Recording + transcripts\n\n**Record Calls** is ON by default. Recordings live on Vapi; transcripts\nland in your Voxility inbox. Turn off if you're in a jurisdiction with\nstrict consent requirements you haven't met.\n\n## End-call phrases\n\nWords or phrases that, when the caller says them, gracefully end the\ncall. Default is empty — add common ones like `goodbye`, `thanks bye`,\n`hang up` to avoid awkward \"sorry I didn't catch that\" loops at the end.\n\n## Max Call Duration\n\nHard cap in minutes. 10 is a reasonable default; 30+ makes sense for\ncomplex sales calls but costs more per call.\n\n## Voice Tools\n\nThe voice agent automatically uses the same tools configured on the\n[Tools](/help/a/tools) tab, **plus** a handful of voice-specific ones:\n\n- `get_available_slots` (voice-optimised)\n- `book_appointment` (voice-optimised)\n- `tag_contact`\n- `send_sms_followup` — queues a text after the call ends\n\n## Common gotchas\n\n- **No bookings?** Check the Tools tab — you need a connected calendar\n  AND booking tools enabled. The test-call panel flags this.\n- **Voice sounds robotic?** Lower stability to 0.3–0.4 for more expression.\n- **Agent talks over the caller?** Turn endCallPhrases off or lengthen the\n  max duration — it may be ending calls too eagerly.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/voice","publishedAt":"2026-04-20T13:51:56.140Z","updatedAt":"2026-06-26T03:30:01.776Z"},{"slug":"working-hours","title":"Working hours: when the agent is allowed to reach out","summary":"Define the time window when the agent can send proactive messages. Inbound replies always send.","body":"Working hours define when the agent is allowed to send **proactive**\nmessages. Inbound replies always send — if a contact messages you at 3am,\nthe agent replies at 3am.\n\n## What working hours control\n\n- **Triggers** — respect the window. A trigger that fires outside hours is\n  held until the window opens.\n- **Follow-ups** — respect the window. Step scheduled for 3am → pushed to\n  9am (or whenever you open).\n- **Agent-initiated follow-ups** (`schedule_followup`) — respect the window.\n\n## What they don't control\n\n- **Inbound replies.** If a contact messages, the agent replies. Full stop.\n- **Manual sends from the Inbox.** You clicking send is your decision.\n- **Handover notifications.** Notifications to you are always real-time.\n\n## Fields\n\n- **Enabled** — turn the whole thing on/off\n- **Start hour / End hour** — 0–24, in the agent's configured timezone\n- **Working days** — tick the days the agent is active\n- **Timezone** — IANA timezone string (e.g. `America/New_York`). All\n  times above are interpreted in this zone.\n\n## Example configurations\n\n**B2B agent, US East Coast business hours:**\n- Start 9, End 18, Mon–Fri, `America/New_York`\n\n**Global consumer agent, near-24/7 but quiet overnight:**\n- Start 7, End 22, Mon–Sun, contact's local timezone (coming soon)\n\n**Aggressive sales agent, always on:**\n- Disabled entirely — treat every minute as fair game\n\n## Design principle\n\n**Respect the ask.** If someone opts into being contacted, they're still\nasleep at 3am. The agent's window shouldn't be your window — it should be\nthe *contact's* window. Default to restraint; you can always loosen later.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/working-hours","publishedAt":"2026-04-20T13:51:56.521Z","updatedAt":"2026-06-26T03:29:59.135Z"},{"slug":"needs-attention-queue","title":"Needs Attention: the review queue for flagged conversations","summary":"One page that surfaces every conversation your agent couldn't handle — paused, errored, fallback-answered, stalled. Act on any row inline without leaving the page.","body":"The **Needs Attention** page (sidebar → Needs Attention) is a single\nlive queue of every conversation a human should look at. It refreshes\nevery 30 seconds and pulls from four sources so nothing falls through\nthe cracks.\n\n## Spotting items without visiting the page\n\nThe sidebar link carries a **red count badge** whenever there are\nflagged items — same shape as an iOS app icon notification. Zero\nmeans the badge is hidden; anything over 99 caps at `99+`. Same\ntreatment on the **Approvals** link if you're using the\n[approval queue](/help/a/human-handover-notifications#approval_pending).\nThe count polls every 30 seconds from the same endpoint the page\nuses, so the number on the badge is always the current queue depth.\n\n## What shows up here\n\n**1. Paused conversations** — anything where a [stop\ncondition](/help/a/stop-conditions) tripped or the agent called\n`transfer_to_human`. The reason is shown in plain English — no\nmore decoding `SENTIMENT:hostile` or `KEYWORD:stop`. You see\n\"Hostile sentiment\" with a one-line explanation of what the agent\nmatched on.\n\n**2. Errored conversations** — a turn where the agent threw during\ntool execution (GHL 500, rate limit, auth failure). Error text is\nshown so you can fix the root cause, not just read the symptom.\n\n**3. Fallback-answered conversations** — turns where the agent used\nits fallback message because it didn't know the answer. If you see the\nsame fallback over and over, that's a signal to add [knowledge](/help/a/knowledge).\n\n**4. Stalled conversations** — threads over 10 turns without a\nresolution. The agent's still replying but nothing's converging; worth\na human eye.\n\n## Actions on each row\n\nEvery paused row with an agent has three options:\n\n- **Resume agent** (green) — hand the conversation back to the\n  agent. Opens a modal where you can leave a context note the\n  agent will see on its very next reply. See the\n  [handoff workflow](/help/a/takeover-and-resume-handoff) for the\n  full walkthrough.\n- **Take over** (outline) — pause the agent under your name. Opens\n  the same modal with a reason field so you capture *why* you're\n  stepping in for audit trail.\n- **View contact** — deep-link into the contact detail page for\n  direct inbox access (the old flow).\n\nErrored / fallback / stalled rows don't have the Resume + Take over\nactions — there's no paused agent to resume or take over from. They\nsurface for context only, with the View contact link to dig in.\n\n## Filters\n\nClick any of the four summary chips (Paused / Errors / Couldn't\nanswer / Stalled) at the top to filter the list to that category.\nClick the same chip again to clear.\n\n## Who gets notified\n\nA **needs_attention** notification fires on every workspace notification\nchannel (Slack, Discord, email, SMS — configured under\n[Integrations](/help/a/human-handover-notifications)) the moment a\nconversation pauses. The review queue is where you go *after* the\nping lands. The sidebar badge is the at-a-glance indicator in between.\n\n## The `needs-attention` tag\n\n[Stop conditions](/help/a/stop-conditions) that trip optionally tag\nthe contact with `needs-attention` (on by default, configurable\nper condition). This is a regular GHL tag so:\n\n- You can search for it in GHL directly\n- You can build workflows that trigger on it\n- You can filter reports on it\n- It persists even after a human takes over — useful for retro\n  analysis (\"how many of our opts-out tagged needs-attention in the\n  week before they unsubscribed?\")\n\nUntag manually when the issue's resolved, or bake it into a recovery\nworkflow that clears the tag on completion.\n\n## Patterns for handling the queue\n\n- **One-human-on-call.** Dedicate one person per timezone to clear the\n  queue each morning. 5 minutes a day beats a 2-hour firefight weekly.\n- **Route by type.** Errored conversations go to a support engineer;\n  paused-for-sentiment conversations go to account managers. Use the\n  needs-attention notifications to fork the signal.\n- **Turn fallback spam into knowledge.** If the same question keeps\n  hitting fallback, the agent's knowledge base is missing a doc.\n- **Resume with a note, not a click-and-pray.** When you unpause an\n  agent, use the modal's note field to tell the agent what the\n  human-conducted part of the conversation covered. Otherwise the\n  agent will likely re-ask questions the human already answered.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/needs-attention-queue","publishedAt":"2026-04-27T22:57:27.680Z","updatedAt":"2026-06-26T03:30:10.159Z"},{"slug":"takeover-and-resume-handoff","title":"Taking over and resuming: the handoff workflow","summary":"When your agent flags a conversation, you can take over under your own name or resume the agent with a context note it reads on its next reply.","body":"When the [Needs Attention queue](/help/a/needs-attention-queue) shows a\npaused conversation, you have three choices: take it over, resume the\nagent with a note, or ignore it. This article covers when to use each\nand how the agent actually receives your guidance.\n\n## Where handoffs happen\n\nAny row on the **Needs Attention** page that represents a paused\nagent (sentiment stop, keyword stop, `transfer_to_human` call,\nmanual pause, etc.) shows two buttons:\n\n- **Resume agent** — green. Hand control back to the agent. The\n  agent replies to the contact's next inbound.\n- **Take over** — outline. Pause the agent under your name and\n  log a takeover record. The agent stays paused until someone\n  resumes it explicitly.\n\nBoth open the same modal. The modal also surfaces the **humanised\npause reason** at the top — \"Hostile sentiment,\" \"Keyword matched\n(stop, unsubscribe),\" \"Agent asked for help,\" etc. — so you know\nwhat you're deciding on before you click.\n\n## Resume agent — the common path\n\nMost \"flagged\" conversations don't actually need a human to step\nin. They need a human to look at the flag, decide it's fine, and\nhand it back — sometimes with context the agent should carry\nforward.\n\n**Example — hostile sentiment false positive:**\n\nContact texts: *\"That's the worst thing I've ever heard. I love it.\"*\n\nThe [SENTIMENT](/help/a/stop-conditions) stop condition fires on\nthe word \"worst.\" The agent pauses. You look at it, realise they\nwere being sarcastic, and click **Resume agent**. You type in the\nmodal:\n\n> *\"They're being sarcastic — they love the product. Keep going.\n> No handholding needed.\"*\n\nClick Resume. The agent unpauses and sees your note on its very\nnext reply. It continues the conversation with full context.\n\n## Two ways to resume — wait vs send now\n\nThe Resume modal has a **\"Send a follow-up message now\"** checkbox.\nThis is the key control that decides what happens immediately\nafter Resume:\n\n- **Unchecked (default) — wait for the next inbound.** The agent\n  flips to ACTIVE state, your handoff note is saved to memory, but\n  nothing visible happens yet. When the contact's next message\n  arrives, the agent reads it + your note, then replies. Use this\n  when the conversation was already paused waiting for the\n  contact's response.\n\n- **Checked — agent sends a follow-up now.** The agent composes\n  an outbound message using the handoff note as context and sends\n  it on the channel you pick in the dropdown. Mirrors the\n  AI-generated [trigger](/help/a/triggers) flow — same prompt\n  scaffolding, same working-hours guard. Use this when you need\n  the agent to reach out proactively, e.g. after you finished a\n  phone call with the contact and want the agent to follow up by\n  SMS.\n\nIf [working hours](/help/a/working-hours) are enabled on the\nagent and the current time is outside the window, the follow-up\nis **skipped** (the agent is still unpaused; the note is still\nsaved). The modal tells you this so you can choose whether to\nwait for the next window or disable working hours.\n\n### When to leave \"Send now\" off\n\n- The contact was mid-sentence when the pause fired — they'll\n  reply again on their own\n- You just took over for 5 minutes, you're handing back before\n  the contact has noticed the pause\n- You want the agent ready-but-quiet\n\n### When to tick \"Send now\"\n\n- The conversation has been idle for hours and you want momentum\n- You finished a phone call with the contact and the agent\n  should reinforce what you agreed on by text\n- The contact never messaged back after the stop-condition hit\n  and you need the agent to break the silence\n\n## Take over — when the agent shouldn't come back alone\n\nUse **Take over** when you want to handle this conversation\nmanually and not leave it up to the agent to pick up again\nautomatically.\n\n**Example — angry contact threatening a lawyer:**\n\nContact says *\"I'm going to call my attorney.\"* SENTIMENT fires.\nYou click **Take over** with the reason:\n\n> *\"Handling directly, will update when resolved.\"*\n\nThe conversation stays paused. You reply to the contact yourself\nfrom the Inbox. When you're done, return to Needs Attention\n(or the contact page) and click Resume agent — this time with a\nnote telling the agent what happened:\n\n> *\"Contact and I reached agreement on the refund. They'll wait\n> 7 days for the credit to clear. Confirm receipt once they\n> respond. Do not bring up the complaint again.\"*\n\nThe agent resumes, reads the handoff note, and picks up from the\nnew baseline.\n\n## How the agent sees your note\n\nWhen you resume with a note, it's stored in the contact's memory\nunder a category called `handoff_context`. That entry gets\ninjected into the agent's system prompt on every subsequent turn\nunder the heading **\"What You Already Know About This Contact\"**:\n\n```\n## What You Already Know About This Contact\n\n- handoff_context: A human just handed this conversation back to\n  you. Their note: \"Contact and I reached agreement on the refund.\n  They'll wait 7 days for the credit to clear. Confirm receipt\n  once they respond. Do not bring up the complaint again.\"\n  Treat this as essential context for your next reply; do not\n  re-open topics the human has already addressed.\n```\n\nThe agent reads this alongside your system prompt, persona, and\nknowledge base on every turn. Instructions like \"don't re-open the\ncomplaint\" reliably stick because the agent sees them fresh each\ntime.\n\n## What makes a good handoff note\n\n- **Summarise what the human leg of the conversation covered.**\n  Not verbatim — just the outcome and any commitments made.\n- **Tell the agent what NOT to do.** \"Don't re-ask about their\n  budget\" prevents the agent from wiping your hard-won progress.\n- **Note any time-sensitive commitments.** \"They'll follow up in\n  7 days\" or \"I promised a callback at 2pm Thursday\" — the agent\n  will honour these.\n- **Don't dump customer PII you didn't get permission for.** The\n  note goes into memory which is visible to anyone with access to\n  this contact's record in Voxility.\n\n## Takeover without a follow-up note\n\nIf you take over and then decide you don't want to resume the agent\nat all (e.g. you converted the lead, you closed the complaint,\nthey're going to deal with it on their end), leave the conversation\npaused. It drops off the Needs Attention queue once the\nconversation stalls or the contact marks it done — nothing else\nhappens. The agent won't spontaneously reply.\n\nYou can also apply an opt-out tag via [rules](/help/a/rules) or\nmanually in GHL to permanently stop outbound to that contact.\n\n## Finding the handoff history\n\nEvery takeover and resume writes an audit trail entry with the\noperator's identity, the note they left, and the timestamp. Visible\nin two places:\n\n- **Audit log** (sidebar → Audit Log) — workspace-wide timeline\n- **Contact detail page** — per-contact history with the same notes\n\nUseful for post-mortems (\"why did we drop this lead?\") and for\nonboarding new operators (\"this is how the team handles hostile\ncontacts\").\n\n## Keyboard-friendly workflow\n\n- Click **Resume agent** on the row\n- Type the note (autofocus is on the textarea)\n- **Enter** submits (via the form's default-submit behaviour)\n- Row disappears from the queue\n- Sidebar badge decrements by 1\n\nMost handoffs should take under 15 seconds end to end.\n\n## The badge on the sidebar\n\nThe red count next to **Needs Attention** in the left nav is the\nnumber of rows currently on the queue. It polls every 30 seconds\nand decrements when you resolve a row. If the number keeps\nclimbing, that's usually a sign of:\n\n- A [stop condition](/help/a/stop-conditions) firing too\n  aggressively (dial back the keyword list or the sentiment\n  match)\n- An agent too quick to call `transfer_to_human` (tighten its\n  instructions so it tries harder before bailing)\n- A real external change — e.g. a bad batch of leads that are all\n  triggering the same fallback\n\nTreat a rising badge as a signal to investigate, not just to\nclear.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/takeover-and-resume-handoff","publishedAt":"2026-04-27T22:57:28.056Z","updatedAt":"2026-06-26T03:30:08.068Z"},{"slug":"human-handover-notifications","title":"Human handover notifications: where the pings go","summary":"Configure Slack, Discord, email, and SMS destinations for agent pauses, errors, and transfer_to_human calls.","body":"Whenever the agent pauses a conversation, calls `transfer_to_human`,\nor errors out, we fire a notification. This article covers where those\npings go and how to wire them up.\n\n## Four notification channels\n\nConfigure under **Settings → Integrations → Notifications**:\n\n- **Slack** — OAuth install, channel picker, posts rich messages\n  with a deep link to the conversation\n- **Discord** — paste a webhook URL (Server → Integrations →\n  Webhooks → New Webhook), we post embeds\n- **Email** — any inbox, one or many. Best for long-tail events you\n  check asynchronously\n- **SMS** — a phone number that gets texted for urgent events.\n  Keep this for true escalations so the noise doesn't train your\n  team to ignore it\n\nYou can wire up any combination. Most operators use Slack + email\nfor routine, SMS for severe only.\n\n## The events\n\n- **`needs_attention`** — a conversation paused itself. Fires for:\n  stop conditions tripping, fallback-with-transfer, manual agent\n  pause. Links to the [Needs Attention queue](/help/a/needs-attention-queue).\n- **`human_handover`** — the agent called `transfer_to_human`.\n  Fires with the agent's summary of *why* (pulled from the tool\n  call's reason argument), so the human picking up has context\n  without reading the whole thread.\n- **`agent_error`** — a turn errored out. Includes the error\n  message so you can debug without screen-sharing.\n- **`approval_pending`** — an outbound reply was held by the\n  [approval queue](/help/a/simple-vs-advanced-agents) for human\n  review. Time-sensitive — these block real outbound traffic until\n  a human clicks approve.\n\nEach event has a severity: `info`, `warning`, `error`. Wire\nintegrations to route severity accordingly (errors to an on-call\nSlack channel, info to an email digest).\n\n## Per-event subscribe\n\nEach integration has per-event toggles so you can wire Slack for\n`needs_attention` only, email for `agent_error` only, SMS just\nfor `approval_pending`. Default is \"all events to all channels\",\nwhich is noisy — narrow it down after the first week.\n\n## What's in the payload\n\nAll notifications include:\n\n- Agent name\n- Contact ID (last 6 chars shown, full in the link)\n- Reason / body (truncated to ~200 chars)\n- Deep link to the conversation in the Inbox\n- Timestamp + severity\n\n## Testing\n\nEach integration has a **Send test** button on its config row. Fires\na real notification with dummy data so you can verify formatting\nwithout waiting for an agent to pause.\n\n## When notifications feel spammy\n\nTwo patterns:\n\n- **Narrow subscriptions.** Don't send every event to every channel.\n  Slack for `needs_attention`, email for everything else.\n- **Tune stop conditions.** If the same stop condition fires 50 times\n  a day, the condition is miscalibrated. Either loosen it (lower\n  sensitivity) or handle it differently (workflow enrol instead of\n  pause — see [stop conditions](/help/a/stop-conditions)).\n\n## Privacy note\n\nNotifications include contact IDs + short message snippets. If you're\nin a regulated industry (HIPAA, PCI), prefer email+SMS to a dedicated\nadmin inbox over Slack/Discord — the latter are easier to accidentally\nover-share.","category":{"name":"Agents","slug":"agents"},"videoUrl":null,"url":"https://app.voxility.ai/help/a/human-handover-notifications","publishedAt":"2026-04-27T22:57:28.433Z","updatedAt":"2026-06-26T03:30:08.577Z"}]}