{
"flowId": "your-flow-id",
"name": "Session link",
"duration": 3600,
"verifiedExtraInternalParams": {
"userId": { "type": "jwt-claim", "key": "sub" },
"accountId": { "type": "jwt-claim", "key": "accountId" }
}
}
```
* **`duration`**: Link lifetime in seconds (must be positive, maximum 6 hours)
* **`verifiedExtraInternalParams`**: Maps parameter names to JWT claim extraction rules. Dial AI reads the specified claim from the caller's verified JWT and bakes it into the link. If the claim is missing or not a string, the request fails.
This combines the security of JWT verification with the simplicity of a pre-built chat link — the frontend just receives a UUID and doesn't need to handle tokens at all.
### When to Use This
* You want the simplest possible frontend — just a chat link UUID, no token handling
* You need per-user or per-session chat links with guaranteed context
* You want to limit which parameters the client can influence via `settableInternalParams`
***
## Comparison
| | External JWT | Server-Side Verification | Backend-Created Links |
| - | - | - | - |
| **Frontend complexity** | Low — pass existing JWT | Low — call your backend first | Lowest — just a UUID |
| **Backend work** | None (configuration only) | Moderate — verification endpoint | Moderate — link creation endpoint |
| **Identity source** | JWT claims | Your system of record | Your system of record or JWT claims |
| **Context flexibility** | All JWT claims available | Full control | Baked at link creation |
| **Session lifetime** | Per-token expiry | Per-link (optional expiry) | Per-link (optional expiry) |
## Using Context in Flows
Regardless of which approach you use, the verified context arrives in your flow as **internal parameters**. Functions can access these values as inputs by declaring them as [internal parameters (context parameters)](/functions-and-events#inputs). For example, a "Look Up Account" function could take `userId` as an internal parameter and use it to query your database — knowing that the value was verified and cannot have been tampered with by the end user.
# Internal Contacts
Source: https://docs.dialai.ca/internal-contact
Pre-configured destinations the AI agent can transfer customers to
**Internal Contacts** are the phonebook of people and teams the AI agent can transfer a customer to during a conversation — supervisors, specific departments, escalation paths, on-call rotations. Configure them once; the agent (or a supervisor in [Live View](/live-view)) can pick from the list mid-call.
## Where Internal Contacts live
Internal Contacts are managed under **Settings > Operations > Internal Contacts**. The Operations page documents the management interface in detail — see [Operations > Internal Contacts](/operations#internal-contacts).
Each entry has:
| Field | Description |
| - | - |
| **Name** | The display name shown when initiating a transfer. |
| **Phone Number** | The number to dial when this contact is picked. |
## Using Internal Contacts during a live call
From the [Live View](/live-view) page or a transcript detail view:
Click a conversation in Live View or open a conversation from the Inbox.
Use the call-monitoring actions to initiate a transfer.
The transfer dialog lists every Internal Contact. Pick the right one and confirm.
The agent (or supervisor) doesn't have to remember or look up phone numbers — every approved destination is one click away.
## Internal Contacts vs Points of Contact
A common point of confusion:
* **Points of Contact** are *incoming* channels — phone numbers customers call to reach you.
* **Internal Contacts** are *outgoing* transfer destinations — phone numbers your AI agent dials when handing off a customer to a human team.
The two never overlap.
## Internal Contacts vs Internal Agents
A separate concept that sometimes confuses operators:
* **Internal Contacts** (this page) are human destinations for transfers.
* **Internal Agents** are back-office AI agents your team uses internally — for reporting, analysis, and back-office automation. They never face customers. See [Agents](/agents).
## Tips
* **Use clear names.** "Billing Supervisor" beats "Joe's Desk" — the agent reads these aloud and operators pick from them under time pressure.
* **Keep the list short.** Every transfer destination adds cognitive load when picking. Aim for under a dozen well-defined options rather than a phone-tree dump.
* **Review quarterly.** People move teams, departments reorganize, escalation paths change. Internal Contacts decay quickly if not curated.
***
## Related
Manage Internal Contacts alongside Skills and Do-Not-Call.
Initiate transfers from a live call.
Internal back-office AI agents (different concept).
# Introduction
Source: https://docs.dialai.ca/introduction
What Dial AI does and how the pieces fit together
Dial AI runs AI agents that talk to your customers over voice, SMS, email, web chat, and other social-media platforms. You design what each agent says and does as a **flow** — a graph of conversation states with instructions, function calls, and rules for when to hand off to a human. You wire the flow to a **point of contact** (a phone number, email address, web widget, etc.), publish it, and watch it work.
When the AI can't handle something, it transfers the conversation to a human agent — with the full transcript, the customer's history, and any data the AI collected. Human agents pick up the conversation in their **inbox**; supervisors watch live traffic in **live view** and review completed conversations in the archive.
These docs cover the operator surface: building flows, connecting channels, monitoring conversations, and tuning what's in production.
## New here? Take the tour
A quick look around the platform: where everything is, and what each part is for. Then read the Getting started handbook for a step-by-step guide to your first days.
Open or download the PDF
## Quick start
Glossary of flows, states, transitions, agents, points of contact, and more.
A guided walkthrough of the flow editor, end to end.
Monitor in-progress calls, listen in, and step in when needed.
Handle transcripts that need human review or follow-up.
## How operators use Dial AI
Use **Flows** to lay out conversation paths — greetings, intents, branches, and handoffs. Use **Thoughts** to express *how* the agent should think at each state in plain language. Ground the agent in your own knowledge by uploading **Documents** or connecting an S3 / Confluence source.
Wire a **Point of Contact** — a phone number, SMS line, email address, web widget, or Slack workspace — to the flow. Each channel can run its own flow, or share one across many.
Run **Test Scenarios** to assert behavior end-to-end. Use the in-product chat sandbox for quick iteration. Publish a flow only when its tests pass.
The **Dashboard** shows day-to-date and live operational metrics. **Live View** gives you a real-time pulse on every in-flight conversation. **Conversations** is the searchable archive of everything that already happened.
Use call review criteria, flagged conversations, and analytics to identify gaps. Refine flows, add documents, retrain — and ship the new version when you're confident.
## What you can build
Branching conversation flows with state-level instructions, function calls, and human-handoff rules.
Voice, SMS, email, web chat, and Slack — each with its own routing and schedule.
Choose or tune the synthetic voice that represents your brand on every call.
Run AI-driven outbound voice or email campaigns against a manifest of contacts.
Upload documents or sync from Confluence and S3 so agents answer from your sources of truth.
Put a web widget on your site, or call the REST API to plug Dial AI into your systems.
## Looking for something else?
* The **Building & Managing Flows** group covers everything about designing agents — start with [Key concepts](/keyconcepts) if you're new.
* The **Monitoring** group covers the day-to-day operator views — Dashboard, Conversations, Live View, Inbox.
* The **Settings** group covers tenant-wide configuration — users, permissions, theming, environment variables.
Short videos and handbooks for every part of the platform, in one place.
Need help that isn't in the docs? Email [support@dialai.ca](mailto:support@dialai.ca).
# Issues
Source: https://docs.dialai.ca/issues
Track bugs, requested flow changes, and observations, and turn review findings into applied fixes
**Issues** are your tenant's tracked work items: an incorrect response caught during call review, a requested flow change, an investigation to run, or an observation worth recording. Each issue carries a status, a priority, a comment thread, and attachments, so findings survive across runs and hand off cleanly between people and agents.
The page has a second tab, **Agent Notes**: a shared scratchpad of durable context (patterns noticed, decisions made, fixes applied, things deliberately ignored). A note is reference memory with no action attached; an issue is a work item someone should act on.
## Accessing Issues
Navigate to **Issues** in the left sidebar.
## What's on the page
The issues table shows every issue in the tenant.
| Column | What it shows |
| - | - |
| **Status** | Where the issue is in its lifecycle (see below). |
| **Title** | Summary line, plus the issue number and age. |
| **Type** | Flow change / Incorrect response / Observation / Investigation. |
| **Priority** | Low / Normal / High / Urgent. |
| **Opened by** | The person, or agent, that filed it. |
| **Updated** | Last activity. |
Filter by status, priority, or type using the controls above the table, and click **Create Issue** to file one manually.
## Inside an issue
Click any row to open the issue. The left column holds the **description** and a running **activity** feed: every status change and comment, oldest first. The right rail is where you work the issue:
* **Status / Priority / Type**: change any of them inline from the dropdowns.
* **Attachments**: link the issue to the things it's about: paste a **transcript** ID, or search for a **flow**, **test scenario**, or **related issue**. A reviewer can then jump straight from the issue to the exact call, flow, or test it concerns.
* **Comment**: add context to the thread; each comment is stamped with who wrote it and when.
## Issue lifecycle
| Status | Meaning |
| - | - |
| **Open** | Filed, not yet picked up. |
| **In progress** | Someone is actively working it. |
| **Verifying** | A fix has been applied and is being checked, and issues move here automatically when a proposed change is applied. |
| **Resolved** | Fix confirmed. |
| **Closed** | Done, no further action. |
| **Won't fix** | Deliberately not acting; the reasoning lives in the comments. |
## Comments and attachments
Every issue has a flat comment thread for discussion. Issues can also attach to the things they're about: transcripts, flows, test scenarios, and other issues. A reviewer can jump straight from "the agent said the wrong thing" to the exact call where it happened.
## Who files issues
* **Your team**, via **Create Issue**.
* **The review agent**, when call review flags a conversation that needs a fix rather than just a flag.
* **Internal agents**, which can open and update issues as they work so their findings are handed off with root-cause summaries and reproducible steps.
## Proposed changes: closing the loop
The most important thing attached to an issue is a **proposed change**: a structured fix proposal, distinct from the free-text comments. It carries the root cause, the precise change, an acceptance test, and risk/rollback notes.
The most common author is the review agent: when a flow accrues review corrections, they're distilled into a suggested call-review-guidance update and filed as a proposed change on a flow-targeted issue.
A proposal moves through its own statuses: **proposed**, then **approved / needs changes / rejected**, and finally **applied** or **superseded**.
### Approve & apply
Reviewing a proposal is one click: **Approve & apply** writes the suggested guidance to the flow and marks the proposal applied, which moves the parent issue to **Verifying**. Review findings become applied flow improvements in minutes, with the issue trail as the audit record.
Applying a proposed change is always a human action. Agents can prepare and file proposals, but never apply them.
## Agent Notes
The second tab holds the shared scratchpad. Notes work like issues without a lifecycle: create them, attach them to transcripts or flows, and search them later. Use notes for context you'd want the next person (or agent) to know; use issues for work that must get done.
***
## Related
Where review flags surface on individual calls.
Verify a fix with test scenarios before resolving.
Where applied guidance changes land.
# Key Concepts
Source: https://docs.dialai.ca/keyconcepts
The vocabulary you need before building flows and agents
This page is the glossary. Everything else in the **Building & Managing Flows** group assumes you know these terms.
## Flow
A **Flow** is a structured sequence of states and transitions that guides a conversation between your AI agent and the customer. A flow has an **initial state**, branches based on what the agent learns during the conversation, and ends when the agent (or a function) decides the interaction is done.
Flows are customer-facing. They run on every channel — voice, SMS, web chat, email, Slack.
See: [Flows](/flows), [Building Your First Flow](/first-flow).
## State
A **State** is one step inside a flow. Each state has:
* A **Thought** — the instructions that tell the AI agent what to say or do here.
* A set of **Functions** the agent is allowed to call from this state.
* Outgoing **Transitions** to other states, each triggered by an **Event**.
The agent stays in a state until a transition fires.
## Transition
A **Transition** is a directed edge from one state to another, triggered by a named **Event**. Transitions are how flows branch — different events from the same state can lead to different next states.
## Event
An **Event** is a named outcome a function can emit. Functions declare the events they may emit; transitions listen for them. Example: a `Lookup Account` function might emit `AccountFound` or `NoAccountMatch`, each driving the flow to a different state.
## Thought
A **Thought** is the natural-language instruction attached to a state. It tells the AI agent how to behave at this point in the conversation — what to say, what data to collect, when to call functions, how to handle edge cases.
Well-written thoughts use strong directives ("must", "will") and reference function names explicitly. See [Designing Thoughts](/thoughts) for the full guide.
## Function
A **Function** is a piece of JavaScript the agent can call. Functions can:
* Take in **parameters** from the agent, from conversation context, or from flow-level static configuration.
* Return a **response** the agent will see.
* Set **context additions** for use by later functions.
* Emit an **event** that drives a state transition.
See [Functions and Events](/functions-and-events).
## Parameter
**Parameters** are data values used inside a flow. Four kinds:
* **Normal parameters** — passed to a function by the agent at call time.
* **Internal (context) parameters** — values set by a previous function or by the runtime, available to later functions.
* **Static parameters** — flow-level configuration (API keys, base URLs, feature toggles). Configured under **Configure Flow > Variables**.
* **Emitted context additions** — context keys a function may write. Declaring these enables UI suggestions and a warning when a function writes an undeclared key.
## Agent
An **Agent** is an internal AI assistant your team uses inside the platform — for analysis, reporting, or back-office tasks. Agents are not customer-facing. They live alongside flows on the Build page for convenience.
See [Agents](/agents).
## Point of contact (POC)
A **Point of Contact** is the channel that connects a flow to the outside world — a phone number, SMS line, email address, [web widget](/web-widgets), or Slack workspace. One flow can serve many POCs; one POC runs exactly one flow at a time.
See [Points of Contact](/points-of-contact).
## Skill
A **Skill** is a named capability that human agents have (e.g., Billing, Spanish, Fraud Assistance). When a flow hands off to a human, the routing engine matches the conversation's required skills against the available human agents.
See [Operations > Skills](/operations#skills).
## Draft vs Published
Every flow has a **draft** (the version you're editing) and zero or more **published** versions. Points of Contact reference a specific published version, so editing a draft never disrupts traffic. Hit **Publish** to cut a new immutable version and update the POCs that should pick it up.
## Test Scenario
A **Test Scenario** is a recorded simulated conversation used to assert flow behavior. Scenarios can be replayed across flow versions to catch regressions before publishing.
See [Testing Flows](/testing-flows).
## Document
A **Document** is reference material the AI agent can search during a conversation. Documents can be uploaded directly, or sourced from a connected S3 bucket or Confluence space.
See [Manage Documents](/manage-documents).
## FAQ
An **FAQ** is a Q\&A pair attached to a flow. FAQs are surfaced to the agent when the customer's message matches the question.
See [FAQ](/faq).
***
## Related
Apply the concepts.
Manage flows.
Every flow setting, explained.
# Live View
Source: https://docs.dialai.ca/live-view
Monitor and manage active customer conversations in real time
The **Live View** page gives supervisors and operators a real-time pulse on every conversation in flight. Watch what the AI agent is doing right now, listen in on voice calls, step in if a conversation goes sideways, and transfer to a human when needed.
For the searchable archive of past conversations, see [Conversations](/conversations). For conversations waiting to be assigned to a human, see the [Inbox](/inbox).
## Accessing Live View
Navigate to **Monitor > Live View** in the left sidebar.
## The conversation list
The conversation table shows every in-progress interaction across every channel. Columns include:
| Column | What it shows |
| - | - |
| **ID** | Unique conversation identifier. |
| **Platform** | Voice / SMS / Web Chat / Email / Slack icon. |
| **Status** | Where the conversation is in its lifecycle. |
| **Duration** | How long it's been going. |
| **Sessions** | How many sessions this contact has had in the past 24 hours. |
| **Risk** | Color-coded estimation of how the call is progressing. |
| **Sentiment** | Detected customer emotion. |
| **Functions** | Functions the AI has called during the interaction. |
Click any row to expand the detail panel beneath it.
### Filters
The filter toolbar at the top lets you narrow the view by **Direction**, **Risk**, **Duration**, **Status**, **Sentiment**, and **Platform**. Useful when a high volume of calls makes it hard to spot the ones that need attention.
## Conversation details panel
Selecting a conversation opens its detail panel below the table. The panel shows:
* **Platform** and **Contact ID** — the channel and customer identifier.
* **Status** — current lifecycle state.
* **Top sentiments** — up to the top three emotions detected so far, filtering out any with a score at or below 0.1.
* **Duration** and **Start** — timing.
* **Live transcript** — messages as they happen, alongside the flow graph showing the current state and the path the conversation has taken so far.
* **Function calls** — every tool the AI has invoked, with inputs and outputs.
You can expand multiple call detail panels at once to keep an eye on several conversations in parallel.
## Monitor mode
Toggle **Monitor** in the top bar to listen in on a voice call without the customer or the AI knowing. This is supervisor-mode listening — useful for quality assurance and training. Turn it off when you're not actively monitoring; it consumes a softphone leg while engaged.
### Call monitoring actions
> These controls are available **only while an AI Agent call is in progress**. If a call is **queued** or **assigned** to a human, these actions are not shown.
### Listen In
Silent monitoring of the live call. The caller and the agent do not hear you.
**How to use**
1. Open the **⋯ Actions** menu on the active call.
2. Select **Listen In**.
**What happens**
* You can hear the conversation in real time.
* Your microphone is not connected to the call.
***
### Take Over
Assume live control of the call. You can hand control back later.
**How to use**
1. Open **⋯ Actions**.
2. Select **Take Over**.
**What happens**
* You are connected as the speaking participant.
* When finished, hand control back to the previous participant (AI Agent or original agent).
***
### Transfer
Send the live call to an **external phone number**.
**How to use**
1. Open **⋯ Actions**.
2. Select **Transfer**.
3. Enter the destination phone number.
4. Confirm to transfer.
**What happens**
* The system dials the destination number and bridges the caller.
* After transfer, control moves to the external destination.
***
### Enqueue
Move the live call into the **human agent queue**.
**How to use**
1. Open **⋯ Actions**.
2. Select **Enqueue**.
**What happens**
* The call is placed back into the queue to be assigned to a human agent.
* The AI Agent stops handling the call.
***
### End
Immediately hang up the call for all parties.
**How to use**
1. Open **⋯ Actions**.
2. Select **End** and confirm.
**What happens**
* The call ends immediately.
* Post-call processes (wrap-up, logging, transcript, etc.) continue as configured.
***
### Add Coaching
Send **coaching notes** to the agent only (not visible to the caller) while the call is active.
**How to use**
1. Open **⋯ Actions**.
2. Select **Add Coaching**.
3. Enter your coaching note and send.
**What happens**
* The note appears to the agent as an internal coaching message during the call.
* The caller never sees coaching notes.
***
### Summary (for quick scan)
| Action | Purpose | Notes |
| - | - | - |
| Listen In | Silent monitoring | No whisper audio |
| Take Over | You become the speaking participant | You can hand control back later |
| Transfer | Send caller to an **external** phone number | Replaces any prior inline refs |
| Enqueue | Return caller to the **human agent queue** | For assignment by a human agent |
| End | Hang up for all parties immediately | Triggers post-call handling |
| Add Coaching | Side-channel guidance to the agent (text only) | Not visible to the caller |
These controls let you intervene on a live call — barge in to talk to the customer, transfer to a human agent, or end the call.
## Settings
The **Settings** button in the top bar opens preferences that tailor your Live View experience:
* **Auto open** — automatically opens new conversations as they appear in the list.
* **Audio alert** — plays a notification sound when a new conversation starts.
* **Auto clear** — removes completed conversations from the list automatically.
* **Max conversations** — caps how many conversations auto-open at once.
These settings are per-user; they don't affect other operators.
## Empty state
When there are no active conversations, the table shows "No Conversations" along with a hint about whether your filters might be hiding live activity. Clear the filters to see everything that's actually in flight.
***
## Related
Past transcripts, searchable and filterable.
Take over a conversation that needs a human.
Aggregate live metrics.
# Manage Documents
Source: https://docs.dialai.ca/manage-documents
Upload files, sync from S3, Confluence, or SharePoint, and curate the knowledge your AI agents can search
The **Documents** page is your tenant's knowledge library — every reference document the AI agent can search during a conversation lives here, whether it came from a direct file upload, an S3 bucket, a Confluence space, or a SharePoint site.
## Accessing Manage Documents
Navigate to **Docs > Manage** in the left sidebar.
## What's on the page
Every document indexed in the tenant appears as a card showing:
* The document name (filename for uploads, page or object name for connectors).
* An **Uploaded** or **Synced** timestamp showing when the index was last updated.
* A **More actions** menu (three-dot) with Download, Sync, and Delete.
The **Upload** button in the top-right opens the upload dialog, where you choose the source type.
## Adding documents
The Upload dialog has four tabs, one per source type. Click any tab to switch.
### File upload
Use the **File** tab for one-off documents you want to manage manually.
Supported formats: **PDF, TXT, HTM, HTML**.
The dialog closes immediately. The document appears in the list and indexes in the background; the card shows a processing indicator until indexing completes.
Updating a file means re-uploading it — there's no in-place file replace. The recommended workflow is: delete the old version, upload the new one, re-attach to any flow that needs it.
### S3 Bucket
Use the **S3 Bucket** tab when your documents already live in S3 and you want the AI agent to read from the source of truth.
The exact name of the bucket — no `s3://` prefix, no region suffix.
The AWS region the bucket lives in (e.g., `us-east-1`, `us-west-2`).
The platform queues an indexing job. Objects in the bucket are pulled, indexed, and turned into searchable documents in the background. Each indexed object appears as its own card in the list.
The tenant must already have IAM access to the bucket configured at the platform level. If indexing fails with a permission error, contact your administrator to grant the platform's service role read access. Buckets not pre-authorized for the tenant cannot be added.
To pick up new objects added to the bucket later, open the bucket's card in the documents list and use **More actions > Sync** to trigger a re-index.
### Confluence
Use the **Confluence** tab to sync documents from a Confluence space. The first time you connect, you'll see an **Install Dial AI App** button — that launches the OAuth flow on Atlassian's side.
Click **Install Dial AI App**. You'll be redirected to Atlassian to authorize. Once approved, the OAuth token is stored against your tenant and you can return to the dialog.
After install, the Confluence tab populates with the spaces the app has access to. Pick the one you want to index.
Add one or more labels to the **Allowed labels** list. When set, only pages with at least one matching label are indexed. Leave empty to index every page in the space.
The platform queues an indexing job. Pages are fetched, indexed, and surfaced as searchable documents. Each page becomes its own document card.
To pick up changes (new pages, edits to existing pages, removed pages), use **More actions > Sync** on a Confluence-sourced document to re-index. Sync is on-demand — the platform does not currently poll Confluence on a schedule.
### SharePoint
Use the **SharePoint** tab to ground your agents in content straight from your organization's SharePoint, with no copy-pasting files out of it and no duplicate libraries to maintain.
The first time you connect, you'll be prompted to sign in with your Microsoft account and grant the Dial AI app access. Access is scoped per site: an admin approves which SharePoint sites the app can read.
After sign-in, choose the SharePoint site you want to index from the list the app has access to.
The platform queues an indexing job. Documents in the site are fetched, indexed, and surfaced as searchable document cards, like any other source.
To pick up changes in SharePoint later, use **More actions > Sync** on a SharePoint-sourced document to re-index. Sync is on-demand.
## Managing existing documents
Click **More actions** on any document card for:
* **Download** — save the indexed source to disk. For Confluence, SharePoint, and S3 sources, this is the fetched copy at index time.
* **Sync** — re-fetch and re-index. Useful after changes in the source bucket or space.
* **Delete** — remove the document from the tenant.
If a document is currently attached to a flow's Documentation tab, deletion is blocked. Detach it from every flow first.
## How documents reach the AI agent
A document in this list isn't automatically used by every flow. To make the agent search a document during a conversation, attach it to a flow under **Configure Flow > Documentation**. See [Flow Documentation](/flow-documentation) for the full configuration reference, including how to tune document amount and query rewriting.
The same documents are also available from [Document Search](/document-search) — a standalone interface for ad-hoc querying.
## Source comparison
| | File upload | S3 Bucket | Confluence |
| - | - | - | - |
| **Best for** | One-off documents you own | Documents already in S3 | Living documentation in Confluence |
| **Auth** | None | Platform-level IAM (admin) | OAuth (per tenant) |
| **Filtering** | n/a (one file at a time) | Whole bucket | Labels (optional) |
| **Sync model** | One-time at upload | On-demand re-index | On-demand re-index |
| **Best when** | Static reference material rarely changes | You already manage versioning in S3 | Your team edits docs in Confluence and wants the agent to pick up updates |
## Supported file formats
For direct file upload: **PDF, TXT, HTM, HTML**. S3 and Confluence connectors handle the file/page types those sources naturally expose.
***
## Related
Search across every indexed document.
Attach documents to a specific flow.
Configure short Q\&A pairs that complement documents.
# Training material
Source: https://docs.dialai.ca/monitoring-training
Short videos and the Monitoring handbook — dashboards, conversation review, Live View, the Inbox, and posting an outage
Learn the day-to-day monitoring views at your own pace. Watch the videos in order or jump to the one you need. The handbook covers the same ground step by step, with screenshots.
## Videos
5 short videos, about 17 minutes in all. Every video has captions.
## Handbook
Read the Monitoring handbook here, open it in a new tab, or download it to keep.
Open or download the PDF
## Related
Every training video and handbook, for every part of the platform, in one place.
The reference pages for this part of the platform.
# Operations
Source: https://docs.dialai.ca/operations
Tenant-wide operational configuration — journey, internal phonebook, do-not-call, and skills
The **Operations** page is the catch-all for tenant-wide operational config that doesn't belong to any single flow. Four tabs: **Journey** (what links a customer's conversations together), **Internal Contacts** (the internal phonebook), **Do Not Call** (outbound suppression), and **Skills** (routing tags for human handoff).
## Accessing Operations
Navigate to **Settings > Operations** in the left sidebar.
## Journey
The Journey tab controls which parameter names are used to **stitch separate conversations into a single customer timeline**. When an agent collects a value like `CISAccountNumber` in one conversation and the same value shows up again next week, the platform threads those conversations together in [Contact History](/points-of-contact#contact-history) — but only for parameters listed here.
Under **Contact History Params**, use the **Configs** dropdown to pick the parameter names that uniquely identify a customer (e.g., `CISAccountNumber`, `ContactId`, `phoneNumber`).
Click **Save** to apply.
Click **Backfill** to re-thread historical conversations using the updated identifier set. Useful right after adding a new parameter.
Parameters chosen here must actually be set by your flow's [Functions](/functions-and-events) during the conversation — otherwise the platform has nothing to stitch on.
## Internal Contacts
The phonebook used by call-center workflows for warm-transfer destinations: escalation lines, supervisor desk phones, and external partner numbers the agent can transfer customers to.
| Column | What it shows |
| - | - |
| **Name** | Display name shown when a transfer is offered (e.g., "Billing Escalation"). |
| **Phone Number** | The number the transfer dials. |
Top-right actions:
* **Create** — add a new internal contact.
* **Delete** (row-level icon) — remove an outdated entry.
For end-to-end coverage of building a dedicated Internal Contact transfer destination — including PSTN vs SIP routing and per-skill steering — see [Internal Contact](/internal-contact).
## Do Not Call
The Do Not Call (DNC) suppression list blocks specific phone numbers from being dialed by outbound campaigns. Numbers on this list are filtered out before the dispatcher places the call.
Opens the bulk-add dialog. Paste one number per line, or upload a CSV/TXT file.
The numbers appear in the list and are immediately respected by [outbound campaigns](/outbound).
Click the delete icon on a row to lift the suppression for that number.
The DNC list is tenant-wide. Removing a number affects every campaign in the tenant — verify the lift is intentional before clicking delete.
## Skills
Skills are short labels (e.g., **Billing**, **Spanish**, **Fraud**) that the routing engine uses to match a handoff to a qualified human agent. Each human agent picks the skills they can handle from their [Personal Configuration](/personal-configuration); when a flow requests a handoff with a specific skill, the router narrows assignment to users whose skill set covers the request.
Only users with the **DialAiAdmin** role can manage skills.
### Creating a skill
Opens the create dialog.
Use a short, recognizable label — it appears verbatim in users' Personal Configuration dropdowns.
The new skill is immediately selectable by users.
### Deleting a skill
Click the delete icon on the skill row, then confirm. Deletion is irreversible.
Deleting a skill doesn't auto-remove it from human agents who already selected it. Those agents keep the tag (struck-through) until they next save their Personal Configuration.
### Best practices
| Practice | Reason |
| - | - |
| Use names ≤ 25 characters. | Fits the multi-select pill UI without truncation. |
| Avoid overlapping meanings ("Customer Support" vs "Customer Assistance"). | Keeps routing logic unambiguous. |
| Review the list quarterly. | Retire unused skills to keep agents' selectors tidy. |
***
## Related
Assign skills and routing settings to operators.
Where each user selects their own skills.
Where the DNC list is enforced.
Where Contact History (driven by Journey params) lives.
# Outbound Campaigns
Source: https://docs.dialai.ca/outbound
Run AI-driven outbound voice campaigns against a list of contacts, or dispatch one-off calls
**Outbound Campaigns** let the AI agent place calls *to* customers — for billing reminders, appointment confirmations, NPS follow-ups, renewals, or anything else where you reach out instead of waiting for inbound. Each campaign attaches a flow to a list of contacts and dispatches calls at a controlled rate.
For one-off calls outside a campaign, see [Dispatch Single](#dispatch-single).
## Accessing Outbound
Navigate to **Outbound > Campaigns** in the left sidebar.
## What's on the page
The campaigns table shows every outbound voice campaign in the tenant.
| Column | What it shows |
| - | - |
| **Name** | The campaign name (e.g., "Late Payment Reminder"). |
| **Type** | Icon for the campaign type. |
| **Active** | Status indicator — paused or running. |
| **Batch Size** | Maximum concurrent calls the dispatcher will schedule at once. |
| **Created** | When the campaign was created. |
| **Flow** | The flow this campaign runs. Click to open it in the flow editor. |
| **Scheduler** | Link into the campaign's scheduler tab. |
Top-right actions:
* **Filter** — narrow the campaigns by name, date, or active status.
* **Dispatch Single** — open the [one-off call](#dispatch-single) form.
* **Create Campaign** — start the campaign-creation flow.
## Creating a campaign
Click **Create Campaign** to start the create flow. You'll attach a flow, configure the dispatcher, and upload a contacts manifest. The contacts table inside the campaign is where the actual call queue lives.
## Inside a campaign
Open a campaign by clicking its row. Each campaign has three tabs: **Contacts**, **Manual**, and **Schedule**.
### Scheduler
Controls when and how aggressively the dispatcher places calls.
* **Batch Size** — maximum concurrent calls the dispatcher will schedule at once. Higher numbers process the contact list faster but consume more telephony capacity.
* **Dispatcher On/Off** — master switch. Flip on when you want the campaign to start placing calls.
* **Calendar** — schedule windows for when the dispatcher is allowed to run. Same calendar widget as the platform-wide [Schedule](/schedule) page, but scoped to this campaign. Use windows like "Tue–Thu 10am–4pm" to respect customer timezones and call-time rules.
The **Edit Queue** button in the top-right opens the queue settings (max concurrent calls, retry policy) in a side panel.
### Contacts Table
The full queue of contacts. Each row is one outbound call.
| Column | What it shows |
| - | - |
| **Phone Number** | The customer's number. |
| **Status** | Queued / Launched / Completed / Failed. |
| **Voice** | The synthetic voice used for this call. |
| **AI Phone Number** | The caller-ID number the call dials *from*. |
| **Parameters** | Per-contact parameters merged into the flow (e.g., FirstName). |
| **Transcript** | Link to the transcript after the call completes. |
| **Launched At** | When the call was dispatched. |
Top-right toolbar:
* **Add** — append contacts to the campaign. The add dialog supports CSV upload and inline entry.
* **Launch** — manually launch the selected contacts (overrides batch-size pacing for emergencies).
* **Relaunch** — re-dispatch contacts that already ran. Useful for retry-after-fix scenarios.
* **Delete** — remove contacts from the campaign.
* **Edit** — modify exactly one contact's parameters before it dispatches.
### Manual launch console
The **Manual** tab is the campaign's on-demand launch console. Instead of waiting for the dispatcher's schedule, launch calls yourself and watch them as they run:
* **Unlaunched**: contacts still queued. Click the launch button on a row to dispatch that call immediately.
* **Currently launched**: calls in flight or just completed, each with a live status and a link to its transcript.
* **Live conversation panel**: select any launched call to watch the conversation in real time, including the agent's messages and (expandable) its thoughts.
Use it for controlled sends ("launch five, listen, adjust, launch the rest"), urgent one-offs inside a campaign, and demos.
## Dispatch Single
The **Dispatch Single** action (top-right of the Campaigns page) opens a one-off launch form for placing a single outbound call without setting up a campaign. Use for ad-hoc test calls, executive follow-ups, or any single dispatch that doesn't justify a campaign.
Required fields:
* **Flow** — the conversation flow to run.
* **Agent Phone Number** — the caller-ID number to dial from.
* **Voice** — the synthetic voice.
* **Customer Number** — the number to dial.
* **Speech to Text Runner** and **Model** — transcription configuration (default: deepgram / flux).
Click **Launch** to place the call.
## Per-contact parameters
Each contact in a campaign can carry parameters that get merged into the flow at call time. The Contacts Table shows these in the **Parameters** column — for example, a `FirstName` parameter so the agent says "Hi Demo A, this is..." instead of a generic greeting.
Set per-contact parameters when uploading the contact manifest, or use **Edit** on a single row to tweak before dispatch.
## Compliance: Do-Not-Call
Manage your tenant's Do-Not-Call suppression list under **Settings > Operations > Do Not Call** — see [Operations](/operations#do-not-call). Before launching a campaign, review the DNC list against your contact manifest to keep prohibited numbers out of the queue.
## Tips
* **Start with a small batch size.** A batch size of 1–3 lets you watch the first few calls before opening the floodgates.
* **Use call-time windows.** Even if your contacts span timezones, the campaign Scheduler's calendar makes it easy to respect "no calls before 9am or after 8pm local time" rules.
* **Set caller-ID to a number the customer recognizes.** Calls from unrecognized numbers get answered far less often.
* **Watch the first conversations.** Use [Live View](/live-view) to monitor the first few real outbound calls — that's where flow bugs surface fastest.
***
## Related
Outbound via email instead of voice.
Configure the caller-ID numbers campaigns dial from.
Watch calls go out in real time.
Manage the Do-Not-Call list.
# Training material
Source: https://docs.dialai.ca/outbound-training
Short videos and the Outbound handbook — launch a voice campaign, read its results, manage Do-Not-Call, and send email campaigns
Learn how to run outbound campaigns and read how they went. Watch the videos in order or jump to the one you need. The handbook covers the same ground step by step, with screenshots.
## Videos
2 short videos, about 7 minutes in all. Every video has captions.
## Handbook
Read the Outbound handbook here, open it in a new tab, or download it to keep.
Open or download the PDF
## Related
Every training video and handbook, for every part of the platform, in one place.
The reference pages for this part of the platform.
# Permissions
Source: https://docs.dialai.ca/permissions
Roles and scope-based access control for your tenant
The **Permissions** page is where administrators define and review the roles that govern who can do what in your tenant. Access is **scope-based**: each role bundles a set of fine-grained scopes (e.g., `transcripts:read`, `flows:publish`, `users:update`), and a user's effective access is the union of every scope on every role they hold.
## Accessing Permissions
Navigate to **Settings > Permissions** in the left sidebar.
## What's on the page
The Roles list shows every role configured for your tenant.
| Column | What it shows |
| - | - |
| **Role Name** | The role's display name. Click to open the role editor. |
| **Permission Count** | How many scopes the role bundles. |
| **Actions** | Delete the role (row-level icon). |
Top-right: **Add Role** opens the new-role dialog.
### Unassigned permissions banner
At the top of the page, the platform surfaces any scopes that **exist in the system but aren't covered by any role in this tenant**. This banner is your hint that a recent platform update added new permissions — review and assign them to the right roles so the features become reachable.
## Built-in roles
The platform ships with a starter set of roles. Common ones:
| Role | Typical use |
| - | - |
| **Admin** / **DialAiAdmin** | Full tenant access — manage users, flows, environment, billing. |
| **Maintainer** | Build and publish flows, manage agents and POCs, run campaigns. Cannot manage users or permissions. |
| **Read-Only** | View dashboards, conversations, transcripts. No edits. |
| **Chatlink** / **Webchat** | Service-account roles used by embedded chat widgets — minimum scopes to start a conversation and send messages. |
| **Customer-Journey** | Service-account role for journey backfill and customer-history sync. |
| **Infrastructure-Manager** | Platform-team role that spans environment and integration management. |
The exact set varies by deployment — your tenant may have additional roles tailored to your organization's structure.
## Creating a role
Opens the role editor.
Pick a name that describes the role's purpose (e.g., "QA Reviewer", "Campaign Operator").
Tick each scope the role should grant. Scopes are grouped by domain (transcripts, flows, channels, etc.) — start narrow and expand as needed.
The role is immediately available in the [Users](/users) page for assignment.
## Editing a role
Click a role's name to open the editor. Toggle scopes and click **Save**. Changes take effect on the next request for any user holding the role.
Removing scopes from a role can lock currently-signed-in users out of pages they have open. Communicate before tightening a role that's in active use.
## Deleting a role
Click the delete icon on the role row, then confirm.
Deleting a role detaches it from every user who holds it. Those users keep their other roles' permissions, but lose anything that was granted only by the deleted role. Check the [Users](/users) page for affected accounts before deleting.
## Assigning roles to users
Roles are assigned from the [Users](/users) page — edit a user, add or remove **Groups**, save. A user can hold any number of roles; their effective permissions are the union.
## Scopes naming convention
Scopes follow a `domain:resource:action` shape. Examples seen across the platform:
* `transcripts:list`, `transcripts:read`, `transcripts:update`
* `flows:config:files:upload`, `flows:config:files:delete`
* `test-scenarios:create`, `test-scenarios:results:read`
* `verified-caller-ids:list`, `verified-caller-ids:update`
The granular shape is intentional: it lets a role like "Read-Only Auditor" grant `transcripts:read` without granting `transcripts:update` or `flows:publish`.
***
## Related
Assign these roles to operator accounts.
Per-user settings users can adjust themselves.
Tenant config gated by these roles.
# Personal Configuration
Source: https://docs.dialai.ca/personal-configuration
Self-service settings each user controls for their own routing, concurrency, and transfer destinations
**Personal Configuration** is the self-service page where every operator tunes how the platform routes conversations to them — their skills, their concurrency limits, and where transferred calls should land when they happen. Settings saved here take effect immediately for all new conversations.
## Accessing Personal Configuration
Navigate to **Monitor > Inbox > Personal** in the left sidebar.
## Skills
The **Skills** multi-select is how you declare what kinds of conversations you can handle. The routing engine matches every skill required by a handoff against the skills you've selected — only users whose skill set covers the request are eligible.
Start broad. Selecting **Customer Assistance** alone makes you eligible for general handoffs. Add specialized skills like **Billing** or **Spanish** only when you're confident you can handle them — narrower selections make you eligible for fewer conversations.
Skill definitions are tenant-wide and managed by admins under [Operations > Skills](/operations#skills). If a skill you need isn't in the dropdown, ask an admin to create it.
## Voice Calls
The **Voice Calls** toggle controls whether the router will send you voice conversations. Off means chat-only routing — useful when you're in a noisy environment or on a call already.
## Max Concurrent Chats
The maximum number of chat conversations the router will assign to you at once. Range 0–10.
| Scenario | Recommendation |
| - | - |
| Quiet hours, full attention available | Higher (3–5). |
| Live-calling and chatting simultaneously | Lower (1–2) so chat doesn't displace voice. |
| Trainee / first week | 1 — focus on quality before scaling. |
## Max Concurrent Emails
Same idea as Max Concurrent Chats, but for email conversations. Range 0–10. Email is typically slower than chat, so concurrency tends to be higher.
## Mobile Phone Number
Where a transferred call should reach you when you're away from your desk — PSTN destination for **Internal Contact** transfers steered at your skills. Use E.164 format (`+1 555 555 0123`); the country selector to the left of the textbox sets the dial code.
Calls only route here when a flow's Internal Contact transfer step matches a skill you've selected. The mobile number isn't used for routing customer calls directly — only for delivering transfers.
## SIP Trunk
The SIP destination for transferring calls to your desk phone or softphone. Numeric IDs and SIP URIs are both accepted.
If both Mobile Phone Number and SIP Trunk are set, the platform attempts the SIP trunk first and falls back to PSTN on failure.
## Saving
Click **Submit** at the bottom of the form. A "User Configuration Updated" toast confirms success. Changes apply to **new** sessions only — anything already routed to you keeps running with its original settings.
## Troubleshooting
| Symptom | Resolution |
| - | - |
| **Skill isn't in the dropdown.** | Ask an admin to create it under [Operations > Skills](/operations#skills). |
| **Transferred calls aren't reaching my mobile.** | Confirm the number is E.164, and that your carrier accepts inbound from your tenant's outbound carrier (some carriers block unfamiliar caller-IDs). |
| **The router keeps skipping me.** | Make sure your status is **Available** (top bar), Voice Calls is on if voice is being routed, and your skills cover the handoff requirements. |
| **Concurrency feels off.** | Remember Max Chats and Max Emails are separate counters — they don't share the cap. |
***
## Related
Where the skills you can select are defined.
How a flow transfers calls to a human via skill-matching.
Where the conversations the router sends you appear.
# Phone payments
Source: https://docs.dialai.ca/phone-payments
Take a card payment from the caller during a voice call, without the card number ever touching Dial AI
Your voice agent can take a payment right on the call. When a caller is ready to pay a balance, the agent hands them to a **secure card capture**, the card is charged through your existing payment provider, and the agent picks the conversation back up with the result. Dial AI never sees the card number.
## How it works
During a voice call, when the caller is ready to pay their balance, the agent offers to take the payment and hands the call to secure capture.
The caller is moved to a secure line to key in their card number, expiry, and security code. The conversation is **paused**, not ended, so the agent is still there when it finishes.
The captured card goes to your existing payment provider and is charged through its API. Dial AI only ever handles tokenized references, never the raw card number.
The call reopens and the agent continues with the outcome: a confirmation code and the last four digits on success, or a failure it can retry or route around. The result is available to the rest of the conversation.
## What the caller hears
The caller is told the payment is being taken securely, then enters their card on the phone. The capture prompts (card number, expiry, security code) are spoken inside the call, and their wording can be tailored to match your brand.
Phone payments run on **voice** calls only, and the amount must be greater than zero. Saving a card for later use is not supported yet.
## Security
* **Dial AI never sees the card number.** The capture is owned by your telephony and payment providers, and the platform only ever handles tokenized aliases.
* **Payments run through your existing provider.** Nothing changes about who processes the money or settles it. Dial AI just orchestrates the hand-off.
* **The card is never on the recording.** Call recording is stopped before the capture and restarted after, so the digits the caller keys never land on tape.
## Related
Configure your voice agent.
Review calls, including the card-payment step.
# Points of Contact
Source: https://docs.dialai.ca/points-of-contact
Connect AI agents to phone numbers, SMS lines, email addresses, web widgets, legacy web chats, and Slack channels
A **Point of Contact** (POC) is the bridge between a customer and a flow. It's the channel — phone number, SMS line, email address, web widget, legacy web chat, or Slack workspace — that customers reach the AI agent through. Each POC ties a channel to exactly one flow and the routing rules that control how interactions are distributed.
## Accessing Points of Contact
Navigate to **Agent > Points of Contact** in the left sidebar.
The page has a tab for each channel type: **Phone**, **SMS**, **Email**, **Web Widgets**, **Web (Legacy)** and **Slack**. It also has a **Verified Outbound Numbers** tab. The **Web Widgets** tab shows only when your role has the `web-widgets:list` permission. The **Verified Outbound Numbers** tab needs `verified-caller-ids:list`.
To get new phone numbers or email addresses provisioned, consult your account representative. Only authorized contact points can be added.
## Channel tabs
Each tab shows a table of configured POCs with the columns relevant to that channel.
### Phone
Voice POCs route incoming phone calls to a flow.
| Column | What it shows |
| - | - |
| **Friendly Name** | An internal label (e.g., "Main Support Line"). |
| **AI Phone Number** | The number assigned to the AI agent. |
| **Flow** | The flow this number runs. |
| **AI Handle / Mode** | Routing mode and AI-handled percentage (e.g., "On (100%)"). |
| **Fallback Phone Number** | Where calls go when the AI does not handle them. |
### SMS
SMS POCs route text messages to a flow. Each row shows Friendly Name, AI Phone Number, and Flow.
### Email
Email POCs handle inbound mail. Additional columns:
* **Email** — the address customers email.
* **Status** — health indicator for the email connection (e.g., **Healthy**).
* **Health Check** — runs a connectivity check against Microsoft Graph or SendGrid.
* **Display Name** — the name shown in the agent's outgoing replies.
* **Handling Mode** — how inbound mail is processed (e.g., **Always Agent**).
### Web Widgets
A web widget puts a chat with a flow on your own website, with a launcher in the corner of each page. This is the way to put chat on a new site. Each row shows the **Status**, the **Widget** name and its flow, the **Visitors** mode, the **Allowed sites** and when it was **Updated**. Click **Create Widget** to add one.
See [Web Widgets](/web-widgets), [Widget appearance](/web-widget-appearance) and [Signed-in visitors](/web-widget-sign-in).
### Web (Legacy)
The legacy web chat (chat links) is deprecated. Chat links still work for now. For a new site, use [Web Widgets](#web-widgets).
Legacy web POCs are chat links you embed on a site. Each row shows the **Chat Code** (a UUID used in the embed snippet), the **Flow** it runs, and the **Voice** assignment (used when the chat supports voice input).
See [iframe integration](/iframe-integration) and [script tag integration](/script-tag-integration) for how to embed a legacy web POC.
### Slack
Slack POCs connect a flow to a Slack workspace. Click **Create Point of Contact** to add one; the create flow walks you through Slack OAuth.
## Creating a POC
Click **Create Point of Contact** in the top-right and pick the channel type. Required fields vary by channel:
* **Friendly Name** — internal label.
* **Channel Type** — Phone, SMS, Email, Web, or Slack. **Web** makes a legacy web chat link.
* **Flow** — the flow this POC routes to.
* **Phone Number** / **Email** / **Chat Code** — the channel-specific identifier.
* **Environment** — Production or Internal Testing.
* For voice channels: **Speech to Text Runner**, **Speech to Text Model**, **Speech to Text Endpointing**, **Voice**, **Background Noise**.
To create a web widget, open the **Web Widgets** tab and click **Create Widget**. See [Create a widget](/web-widgets#create-a-widget).
## Editing a POC
Click the edit (pencil) icon on a row. The Edit Configuration page has three tabs.
### Details
The AI Phone Number is read-only; everything else is editable:
* **Friendly Name** — internal label.
* **Used For** — Production or Internal Testing.
### Routing
Controls how incoming interactions are distributed.
* **Routing Mode** — `On` or `Schedule`.
* **On**: AI is always active. Configure **AI Handle Percentage** (0-100%) to split traffic between AI and fallback. The remaining percentage transfers to the **Fallback Phone Number**.
* **Schedule**: AI is active only during configured time windows. Click **Edit Schedule** to open the schedule editor — see [Schedule](/schedule).
* **Fallback Phone Number** — where unhandled calls go.
### Variants
Variants let you A/B test multiple flow configurations on the same POC. Each variant has:
* **Handle Percentage** — share of calls routed to this variant. Variants must sum to 100%.
* **Draft Flow** — the flow this variant runs.
* **Version** — a specific published version. Leave empty to track the draft (any edit takes effect immediately).
* **Voice** — synthetic voice for this variant.
* **Speech to Text Runner** / **Model** / **Endpointing** — voice transcription settings.
* **Background Noise** — ambient call center sounds during voice calls.
Use **Add variant** to create a new variant; the `×` button removes one.
### Rollouts
Rollouts automate the variant split over time, so changing a live flow doesn't have to be all-or-nothing, and doesn't require you to nudge percentages by hand every morning.
A rollout shifts traffic from your current variant to a new one on a schedule you choose: start the new flow version at a small share of calls (say 10%) and let the platform ramp it automatically to 100% over the period you set. Every change proves itself on a small slice of real traffic before it goes wide.
* **Start small.** The starting percentage is your safety margin: the first calls on the new variant are the ones to review.
* **Watch as it ramps.** Use [Conversations](/conversations) filters to compare the variants while the rollout is running.
* **Interrupt anytime.** Editing the variant percentages directly stops the automatic ramp, which is handy as an instant rollback if something looks wrong.
## Tips
* **Friendly names matter.** "Main Support Line" beats "+1 (555) 555-0101" when you have 30 POCs.
* **Roll out gradually.** Use a [Rollout](#rollouts) to ramp a new flow version from 10% to 100% automatically, or nudge the **AI Handle Percentage** slider by hand.
* **Test before going live.** Set **Used For** to **Internal Testing** while iterating; flip to **Production** when ready.
* **Plan fallback explicitly.** Every Phone POC needs a fallback number — don't leave it empty.
***
## Related
Set time-of-day routing windows.
Pick the AI's synthetic voice.
Put chat on your website.
Run outbound campaigns from a verified caller ID.
# Schedule
Source: https://docs.dialai.ca/schedule
Configure when each phone POC is active and how much AI handles
The **Schedule** page gives you a unified view of when every phone POC in your tenant is active. Configure business hours, after-hours coverage, weekend handling, and AI-vs-human ramp percentages — all from a single calendar.
## Accessing Schedule
Navigate to **Agent > Schedule** in the left sidebar.
## What's on the page
* **Filters panel (left)** — checkboxes for each phone POC, each showing its current routing mode and AI handle percentage (e.g., `ON • 100% AI handle`). Toggle individual numbers to focus the calendar, or use **All phone numbers** to show everything.
* **Calendar (center)** — colored bars showing each POC's active windows. Switch views with the **Month**, **Week**, **Day**, **Agenda** tabs. Use **Today**, **Back**, **Next** to navigate between time periods.
* **Schedules panel (right)** — a summary of total and active schedule windows for the currently selected POCs.
## Routing modes
Every phone POC has a **Routing Mode** set on its [Points of Contact > Edit > Routing](/points-of-contact) tab:
* **On** — AI is always active. The handle percentage applies at every hour of every day.
* **Schedule** — AI is active only during the configured time windows. Outside those windows, AI handle drops to 0% and calls transfer to the fallback number.
Only POCs in **Schedule** mode show colored windows on the Schedule page. POCs in **On** mode appear as a full bar at their constant handle percentage.
## Editing a schedule
Two entry points:
Click a phone POC's bar in the calendar — it opens the schedule editor pre-filtered to that POC.
Edit the POC, switch to the **Routing** tab, set **Routing Mode** to **Schedule**, then click **Edit Schedule**. See [Points of Contact](/points-of-contact#routing) for the full editor walkthrough.
## Creating a schedule window
In the schedule editor:
1. Click **+ New Event** (or drag-select on the calendar to pre-fill the time range).
2. Fill in:
* **Name** — what this window is for (e.g., "Business Hours", "Weekend Coverage").
* **AI Handle Percentage** — share of calls AI handles during this window (0–100%).
* **From** / **To** — the day and time range. Schedule windows repeat weekly.
* **Enabled** — uncheck to disable a window without deleting it.
3. Click **Add**.
### Rules and gotchas
* Each window repeats every week.
* Same-day windows require end-time after start-time.
* Overlapping windows on the same POC aren't allowed.
* Outside any active window, AI handle is **0%** and calls transfer to the fallback number.
### Common patterns
| Pattern | From | To |
| - | - | - |
| Weekday business hours | Monday 9:00 AM | Friday 5:00 PM |
| After-hours coverage | Saturday 5:00 PM | Monday 8:00 AM |
| Night shift | Monday 8:00 PM | Tuesday 5:00 AM |
## Calendar views
* **Month** — the whole month at a glance; good for spotting coverage gaps.
* **Week** — hour-resolution view of a single week; the default for active configuration.
* **Day** — focus on one day; useful for densely-scheduled POCs.
* **Agenda** — list view of upcoming windows.
## Tips
* **Default to Schedule mode for production POCs.** It makes business hours explicit and gives you a calendar you can audit.
* **One window per shift, not one per day.** Use a single Monday-9am→Friday-5pm window instead of five identical daily windows.
* **Disable, don't delete.** Toggle **Enabled** off when an emergency change is needed; that way you can re-enable later without re-typing the times.
***
## Related
Set Routing Mode and Fallback per POC.
Tenant-wide ops: skills, internal contacts, do-not-call.
# Script Tag Integration (Legacy)
Source: https://docs.dialai.ca/script-tag-integration
Instructions on how to integrate Dial AI into your application using a simple script tag.
The customer chat on this page (`renderModal` and a chat ID) is the legacy web chat. It uses a chat link from the **Web (Legacy)** tab of **Points of Contact**. For a new site, use [Web Widgets](/web-widgets). Chat links still work for now, but they are deprecated. This page stays for sites that use a chat link today.
Web Widgets do not replace the [internal-agent embed](#internal-agent-embed-page-aware-integrations) (`renderInternalAgentApp`) on this page.
Dial AI can be embedded in your application via a single script tag. This method gives you a floating chat button (bottom-right) that opens the AI agent in a modal when clicked — your visitors talk to the agent without leaving your application.
## Prerequisites
Before you begin, you'll need:
* A Dial AI chat ID (see [Creating a Chat ID](#creating-a-chat-id) below)
* The backend URL for your Dial AI instance
* A unique anchor ID for mounting the chat button
## Creating a Chat ID
A **chat ID** is the UUID of a Web Point of Contact. Create one under **Agent > Points of Contact > Web (Legacy)** — see [iframe integration](/iframe-integration#creating-a-chat-link) for the step-by-step.
## Basic Integration
Add the following to your HTML file, replacing the placeholder values as needed:
1. Load the widget script in your `` tag:
```html theme={null}
```
Replace `{version}` with a specific release version (e.g. `0.0.1329`) from the [versions manifest](https://cdn.dialai.ca/v1/versions.json).
2. Add the mount point and initialization script:
```html theme={null}
```
## Configuration Options
The `renderModal` function accepts the following configuration options:
* `iconUrl` (string, required): URL to the icon that will be displayed in the chat button
* `chatId` (string, required): Your unique Dial AI chat identifier
* `backendUrl` (string, required): The base URL of your Dial AI instance
* `brandVariants` (object, optional): Custom color scheme for the chat interface (see [Brand Variants](#brand-variants) below)
## Brand Variants
By default, the widget uses the theme configured for the chat link's tenant. If you need to override this to match your site's branding, pass a `brandVariants` object with color values on a scale from 10 (darkest) to 160 (lightest):
```js theme={null}
brandVariants: {
10: "#001018",
20: "#002030",
30: "#003049",
40: "#004062",
50: "#00507a",
60: "#006093",
70: "#0070ab",
80: "#0080c4",
90: "#0090dc",
100: "#00a1f5",
110: "#10adfe",
120: "#2bb6ff",
130: "#45bfff",
140: "#60c8ff",
150: "#7ad1ff",
160: "#95dafe"
}
```
Omit `brandVariants` to use the tenant's default theme.
## CORS Configuration
The widget script is served from our CDN with permissive CORS headers (`Access-Control-Allow-Origin: *`), so it can be loaded from any domain without additional configuration.
## Troubleshooting
* If the chat button doesn't appear, check your browser's console for any error messages
* Ensure the anchor element with the specified ID exists in the DOM when the script runs
* Make sure the chat ID and backend URL are correct
## Example Implementation
Here's a complete example of how to integrate the chat button into a simple HTML page:
```html theme={null}
My App with Dial AI
Welcome to My App
Click the chat button in the bottom right to get help.
```
## Versions
The widget is hosted on our CDN at `https://cdn.dialai.ca/v1/esm/{version}/dial-ai.js`. You can find available versions in the [versions manifest](https://cdn.dialai.ca/v1/versions.json). Pin to a specific release version to avoid unexpected changes.
## Internal-Agent embed: page-aware integrations
In addition to the customer-facing chat (`renderModal`), the same bundle exposes `renderInternalAgentApp` — used to embed an **internal agent** (back-office assistant) into your own internal tooling. This embed exposes two host-page hooks that let the agent become aware of, and act on, the page it's running inside.
### `onNavigate` — let the agent drive page navigation
When an agent tool result includes the field `X-DialAI-Navigation-Path`, the widget invokes your `onNavigate(path)` callback. Use this to wire the agent into your app's router so the agent can say "I've opened the customer record for you" and actually open it.
```html theme={null}
```
The callback fires exactly once per tool completion that contains a navigation path. The path is a string — the host decides how to interpret it (absolute URL, relative route, anchor). If `onNavigate` is omitted, navigation results are silently ignored.
### `onMessageSend` — inject page context with every user message
Before each user message is sent to the agent, the widget calls your `onMessageSend()` callback. Return `{ contextAdditions: string }` and the string is appended to the outgoing user message after a delimiter, so the agent can see what's currently on the page without the user having to type it.
```html theme={null}
```
The widget appends the returned string to the user's message using a `` marker; the agent sees both the original user input and the appended context.
The callback must be **synchronous** — return a value immediately, don't await anything. Use cached/derived values that are already in memory.
Common things to pass via `contextAdditions`:
* The current route, page title, or page-level entity ID.
* The currently-selected item (row in a table, item in a list).
* Active filters or search terms the user has applied.
* The viewport-visible portion of a long document, if the agent should "see what the user sees".
### When to use this vs the chat-link iframe
| | `renderInternalAgentApp` | Customer chat (`renderModal` / iframe) |
| - | - | - |
| Audience | Your internal staff. | Your end customers. |
| Auth | Operator-authenticated session (the host page is already signed in). | Anonymous; uses a Web POC chat link UUID. |
| Page hooks | `onNavigate`, `onMessageSend`. | None — chat is sandboxed in an iframe. |
| Conversation persistence | Backed by the internal-agent SSE stream. | One-shot chat session per visitor. |
Pick `renderInternalAgentApp` when you're building an in-house tool where the agent should *do things* in your app on the user's behalf. Pick `renderModal` (or the [iframe](/iframe-integration)) when you're putting a customer-facing AI agent on a public page.
## ESM vs UMD
The widget is available in two module formats:
* **ESM** (recommended) — loaded with `
```
The widget calls the function before each session start, and again about each 8 minutes to refresh the session. Obey these rules:
* Return a new token on each call.
* Return `null` when nobody is signed in.
* Return in less than 10 seconds. The widget counts no answer as `null`.
* Keep the token under 32 KiB.
An error, a rejected promise, or a value that is not text counts as `null`.
When a customer signs out of your portal, also call `DialAI("logout")`. Then the next person on the same browser does not see the conversation.
### Your backend can sign the token
If your portal has no identity provider that issues JWTs, your backend can sign a short token for the widget:
1. Your backend checks the portal session of the customer.
2. It signs a JWT with HS256 and the shared secret of the provider. Or it signs with its own private key, and you give the public key or a JWKS URL to the provider.
3. It puts the verified values in the claims, for example the account number.
4. It returns the token to the `identity` function of your page.
Give the token a short life, for example 10 minutes, and set **Oldest token, in minutes** to match.
## Test the paths with Act as a customer
**Act as a customer** lets you chat on the **Try it** card as a signed-in customer, with claims that you type. You do not need a token from your portal.
You need the `web-widgets:simulate` permission, and the widget must have at least one sign-in provider.
On the **Try it** card, click **Act as a customer**.
In **Sign-in provider**, select the provider to test.
In **Claims (JSON)**, type the claims of a customer's token. The field starts with a test user at the **User id path**. The maximum is 16 KiB.
Click **Start as this customer**. Then open the launcher on the sample site and chat.
The card then shows what the paths of the provider found in your claims:
* **Visitor id** — **Found**, or the reason the sign-in fails:
* "The path finds nothing in the claims. The sign-in fails."
* "Not an id. Use text that is not empty, or a number. The sign-in fails."
* For an ambiguous path, the number of values and the first values. For example, the user id path `$.accounts[*].number` on the example claims above gives `The path finds 2 values: "1001", "1002". It must find one. The sign-in fails.`
* Each context parameter — one of these:
* **Set**.
* "The path finds nothing in the claims".
* "Does not fit: …" with the schema problem.
* For an ambiguous path, the number of values and the first values, then "It must find one, so the parameter is left out."
The card shows a maximum of five values. When a path finds 50 values or more, the card says "50 or more values".
If a path finds two or more values, the card shows a warning: "A path of this sign-in provider has a mistake. Correct it in the sign-in settings: a real visitor gets the same result, and the widget logs the mistake as an error."
Click **Stop** to chat as an anonymous visitor again. The session of **Act as a customer** is a simulated session. It never shows the real conversations of that customer.
## When a sign-in fails
When the platform refuses a token, the widget gets one of these codes. Your developers can see the code in the network tab of the browser.
| Code | Means |
| - | - |
| `invalid_token` | Not a JWT, a bad signature, an algorithm that the key does not permit, no `exp` or `iat`, or an `iat` or `nbf` in the future. |
| `unknown_issuer` | No provider of the widget has the `iss` of the token. |
| `expired` | The `exp` of the token is more than 60 seconds ago. |
| `too_old` | The `iat` of the token is older than **Oldest token, in minutes**. |
| `bad_audience` | The `aud` of the token does not hold the audience of the provider. |
| `no_user_id` | The **User id path** found no value, two or more values, or a value that is not text or a number. Empty text is not a user id. |
| `context_too_large` | The context parameters are more than 4 KiB of JSON. |
| `identity_required` | A refresh had no token, but the session needs a signed-in customer. The session ends. |
| `user_changed` | A refresh had a token of a different user. The session ends. |
## Best practices
| Practice | Reason |
| - | - |
| Put only the values that the flow needs in the claims. | The values must be 4 KiB of JSON or less. |
| Use a filter to select one value from a list. | A path that finds two values is ambiguous, and the platform does not use it. |
| Test each provider with **Act as a customer** before you go live. | The save check finds only syntax mistakes. |
| Give tokens a short life. | A stolen token is then useful for a short time only. |
## Related
Create a widget and put it on your site.
Presets, colours, fonts and the launcher.
Read context parameters in a function.
Make the parameters that the widget fills.
# Web Widgets
Source: https://docs.dialai.ca/web-widgets
Put a chat with one of your flows on your website, with a launcher in the corner of each page.
A **web widget** puts a chat with one of your flows on your own website. The widget adds a launcher in a bottom corner of each page. A visitor clicks the launcher, and a chat panel opens on the same page.
Web Widgets are the new way to put chat on a website. They replace the legacy web chat (chat links on the **Web (Legacy)** tab, with the [iframe](/iframe-integration) or the [script tag](/script-tag-integration)). Use a web widget for each new site.
A widget has these parts:
* **A flow** — the flow that answers the visitors.
* **Allowed sites** — the sites that can show the widget. No other site can show it.
* **An appearance** — a preset and your changes to it. See [Widget appearance](/web-widget-appearance).
* **Sign-in** — optional. A portal that signs its customers in can tell the widget who the customer is. See [Signed-in visitors](/web-widget-sign-in).
## Find Web Widgets
Go to **Agent > Points of Contact** and select the **Web Widgets** tab.
The tab shows only when your role has the `web-widgets:list` permission. Other actions need other permissions:
| Permission | What it lets you do |
| - | - |
| `web-widgets:list` | See the **Web Widgets** tab and the list of widgets. |
| `web-widgets:read` | Open the page of a widget. |
| `web-widgets:create` | Create a widget with **Create Widget**. |
| `web-widgets:update` | Change a widget: its status, allowed sites, appearance and sign-in. |
| `web-widgets:simulate` | Use **Act as a customer** on the **Try it** card. |
The list has these columns: **Status**, **Widget**, **Visitors**, **Allowed sites** and **Updated**. Active widgets are at the top. Use the **Status** filter to show only **Active** or **Off** widgets. Click a row to open the page of that widget.
## Create a widget
On the **Web Widgets** tab, click **Create Widget**.
In **Name**, type a name for the site or the page that shows the widget. An example is "Billing help on the account page". Each widget in your tenant must have a different name.
In **Flow**, select the flow that answers the visitors.
In **Allowed sites**, type the address of a site, such as `https://www.example.com`. Click **Add**. Do this again for each site that shows the widget.
Click **Create Widget**. The page of the new widget opens.
A new widget is active. Each visitor is anonymous until you set up [sign-in](/web-widget-sign-in). The appearance is the **Classic** preset until you change it.
## Allowed sites
The allowed sites are a security control. On a site that is not in the list, the launcher and the chat panel do not show. If the list is empty, no site can show the widget.
Each entry is an origin: a scheme, a host and an optional port. The widget ignores the path of an address. These forms are permitted:
| Form | Example | Notes |
| - | - | - |
| One site | `https://www.example.com` | The usual form. |
| All subdomains of a domain | `https://*.example.com` | Not permitted on a public suffix, such as `*.co.uk` or `*.github.io`. |
| A site with a port | `https://portal.example.com:8443` | For a site on a port that is not the default. |
| A local test site | `http://localhost:3000` | Only `localhost` and `127.0.0.1` can use `http`. |
A widget has a maximum of 50 allowed sites.
The list in the **Create Widget** dialog starts with the site of the Dial AI dashboard. This lets you try the widget on the **Try it** card at once. Keep this entry while you use **Try it**.
To change the list later, click the edit (pencil) icon beside **Allowed sites** on the page of the widget. Add or remove sites, then click **Save**.
## The page of a widget
The page has these cards: **Try it**, **Appearance**, **Embed code** and **Sign-in**. The side panel shows the **Status**, **Flow**, **Visitors**, **Allowed sites**, **Look**, **Limits** and **Created** date.
### Status
The **Status** switch turns the widget on or off for all sites at the same time.
* **Active: sites show the widget** — each allowed site shows the launcher.
* **Off: no site shows it** — the launcher goes away, and the widget starts no new session.
Use **Off** to stop a widget. The page has no delete action.
### Limits
**Limits** shows the maximum number of conversations that the widget starts in one day (UTC), or **No daily limit**. You cannot change the limit on this page.
## Try it
The **Try it** card shows a sample website with the widget on it. Click the launcher in its bottom corner and chat as a visitor does. A chat on the sample site is a real conversation with the flow of the widget.
* **Start again** loads the sample site again.
* The **Open the sample site in a new tab** icon button opens the sample site in a new browser tab. In the tab, the widget has the full window, so it shows its desktop layout.
When somebody saves a change, the tab shows a bar: **The theme has changed.** or **The widget has changed.** Click **Reload** to show the change.
The sample site cannot show the widget in these conditions. The card then shows the reason.
| Message | What to do |
| - | - |
| This page (…) is not one of the widget's allowed sites, so the widget cannot show here. | Add the site of the dashboard to **Allowed sites**. |
| The widget is off, so no site shows it. | Set **Status** to **Active**. |
| The chat widget is not available on this deployment… | Contact your account representative. |
When the widget has a sign-in provider, you can also chat as a signed-in customer. See [Act as a customer](/web-widget-sign-in#test-the-paths-with-act-as-a-customer).
## Put the widget on your site
On the **Embed code** card, click **Copy**.
Paste the code immediately before the `` tag of each page that shows the widget.
Make sure that the site of each page is in **Allowed sites**.
The embed code has this shape:
```html theme={null}
```
Always copy the embed code from the page of the widget, because it has the correct values for your deployment.
### What visitors see
* The launcher shows in the corner that you set in the appearance.
* On a screen of 480 px or less, the open chat panel covers the full page.
* The **Escape** key closes the panel.
* If the chat cannot load in 15 seconds, the panel shows "The chat could not load." and a **Try again** button.
A page that a visitor opens after a change shows the change. A page that stays open shows the new launcher after a maximum of 30 minutes.
## Control the widget from your page
The embed code also makes a JavaScript function, `DialAI`, on your page. Your page can use it to open the chat, to listen to events, and to give the widget a sign-in token.
### Call `DialAI` before the script loads
To call `DialAI` before the script loads, add a small queue function first. Then call `init` yourself, and remove the `data-tenant`, `data-widget-id` and `data-host` attributes from the script tag:
```html theme={null}
```
Copy the values of `tenant`, `widgetId` and `host` from the embed code of the widget.
Only the first `init` has an effect. The `data-tenant` attribute on the script tag is also an `init`, and it runs first. If you keep the attributes and also call `init`, the widget ignores your `init` and its options, such as `identity`.
### Commands
| Command | What it does |
| - | - |
| `DialAI("init", { tenant, widgetId, host, identity })` | Adds the launcher. `host` and `identity` are optional. |
| `DialAI("open")` | Opens the chat panel. |
| `DialAI("close")` | Closes the chat panel. |
| `DialAI("toggle")` | Opens the panel when it is closed, and closes it when it is open. |
| `DialAI("logout")` | Ends the session of the visitor in the widget. |
| `DialAI("on", event, handler)` | Calls `handler(payload)` for each event of that type. |
Call `DialAI("logout")` when a person signs out of your site. Then the next person on the same browser does not see the conversation of the previous person. The logout works also when the chat panel did not open yet.
To tell the widget who a signed-in customer is, give `init` an `identity` function. See [Signed-in visitors](/web-widget-sign-in#give-the-widget-a-token).
### Events
| Event | Payload | When |
| - | - | - |
| `state` | `{ open }` | Each time the panel opens or closes. |
| `conversation` | `{ event }`, with `event` one of `"started"`, `"ended"` or `"handoff-started"` | When a conversation starts, ends, or goes to a human agent. |
| `message` | `{ direction, text, at }`, with `direction` one of `"received"` or `"sent"` | For each new message. |
In the `text` of a `sent` message, the platform masks sensitive data, such as a card number. Your page never gets the text that the visitor typed.
This example opens the chat from a "Chat with us" link, and records each handoff:
```html theme={null}
Chat with us
```
Put this code after the queue function, so that `DialAI` exists when it runs.
### Style the launcher
Your page can change the launcher with CSS `::part()` rules. Your page cannot change the chat panel or the theme. See [Widget appearance](/web-widget-appearance#style-the-launcher-from-your-page).
## Web Widgets and the legacy web chat
| | Web Widgets | Web (Legacy) |
| - | - | - |
| Where | **Points of Contact > Web Widgets** | **Points of Contact > Web (Legacy)** |
| On your site | One script tag. It adds a launcher and a chat panel. | An iframe or the `dial-ai.js` script with `renderModal`. |
| Which sites | Only the allowed sites. | Any site that has the chat link. |
| Look | Presets and overrides, set on the dashboard. | The tenant theme, or `brandVariants` on the page. |
| Customer identity | Tokens from your portal, checked by the platform. See [Signed-in visitors](/web-widget-sign-in). | Chat links with baked-in context. See [Passing context securely](/integration-context). |
| Status | Current. | Deprecated. Chat links still work for now. |
## Best practices
| Practice | Reason |
| - | - |
| Make one widget for each site or each part of a site. | Each widget has its own allowed sites, look and flow. The name shows in the list. |
| Add only the sites that you own to **Allowed sites**. | Any allowed site can show your flow to its visitors. |
| Test on the **Try it** card before you paste the embed code. | You see the same widget that your visitors see. |
| Set **Status** to **Off** to stop a widget at once. | All sites stop it. You do not have to change each page. |
## Related
Presets, colours, fonts and the launcher.
Tell the widget who your customer is.
All the channels that connect a flow to customers.
Build the flow that answers your visitors.
# Writing Good Documentation
Source: https://docs.dialai.ca/writing-good-docs
How to author reference material the AI agent can actually use
The AI agent doesn't read your documents end-to-end the way a person does. When a customer asks a question, the platform searches your library for the passages most likely to contain the answer and hands those passages — not the whole document — to the model. The way you write and structure documentation has a direct impact on whether the right passage gets retrieved and whether the model can answer from it.
This page lays out the properties that make documentation work well with our retrieval system. Treat it as a working baseline — we will keep iterating as we learn what helps most.
## How retrieval works (in one paragraph)
Each document is split into **large chunks** and embedded into a vector index. At conversation time, the customer's message (rewritten as a search query — see [Flow Documentation](/flow-documentation)) is embedded against that index, and the closest chunks are returned. Before indexing, each chunk is **contextualized**: the platform prepends a short, AI-generated summary that situates the chunk inside the larger document, so that a chunk about "rebate eligibility" still retrieves well for a query about "the Energy Rebate Program" even when the program name isn't repeated locally. This technique is described in Anthropic's [Contextual Retrieval](https://www.anthropic.com/engineering/contextual-retrieval) write-up.
The practical implication: **the model only sees the chunks that come back**. If a chunk is ambiguous on its own, retrieved out of context, or contradicts another chunk, the answer suffers.
## Properties of good documentation
### Self-contained sections
A reader who lands on a single section — with no surrounding pages — should still understand what it's about. Don't rely on "as described above" or "see the previous section". Restate the subject when a new section starts.
> **Less good**: "It must be submitted within 30 days."
> **Better**: "A rebate application must be submitted within 30 days of installation."
Contextualization helps, but the closer a chunk is to standing on its own, the more reliably retrieval and answering both work.
### Clear, descriptive headings
Headings are one of the strongest signals the contextualization step uses to summarize a chunk. Write them like search results, not table-of-contents entries.
> **Less good**: "Overview", "Details", "Other notes"
> **Better**: "Rebate eligibility for residential customers", "How to submit a rebate application", "What to do if your application is rejected"
### One topic per document, when practical
Smaller, focused documents retrieve more accurately than monolithic handbooks. A 200-page policy manual is a worst case — ten 20-page documents on specific topics is much better. If a single PDF mixes billing, outages, and rebate programs, retrieval will sometimes return the wrong section for a given question.
If you can't split a source document, at least give it a strong, descriptive internal structure.
### Consistent terminology
Use the same name for the same thing throughout your library. If one document calls it the "Energy Rebate Program" and another calls it "EnerSave", retrieval has to bridge that gap on every query. Pick one canonical term per concept and stick to it.
Where customers genuinely use a different vocabulary than your documents do, use the **Query Rewriter Context** field on [Flow Documentation](/flow-documentation) to list the synonyms — but reduce vocabulary drift inside the documents themselves first.
### Define acronyms and jargon inline
Spell out an acronym the first time it appears in a section — not just the first time it appears in the document. Remember that the agent may only see one chunk, not the introduction.
> "PV (photovoltaic) systems qualify for the federal credit when..."
### Concrete over abstract
Specific values, names, thresholds, dates, dollar amounts, and procedures retrieve much better than abstract descriptions. If the answer to a likely question is a number or a step list, write the number or the step list — don't paraphrase it.
### Avoid duplication and contradiction
When two chunks cover the same ground with different details, retrieval may return either one — and the agent's answer becomes inconsistent. Prefer a single authoritative source per topic. If you do need duplication (e.g., a quick summary plus a full policy), make sure the two versions agree, and consider whether the summary belongs in an [FAQ](/faq) instead.
### Keep documents current
Stale documentation is worse than missing documentation — the agent will confidently quote outdated policy. Set a review cadence for every document, and prefer connector sources ([S3](/manage-documents#s3-bucket), [Confluence](/manage-documents#confluence)) when the source of truth is already maintained somewhere your team updates regularly.
### Images and tables
Images aren't invisible to the agent — the platform converts each image into an AI-generated text description before indexing — but quality varies. A labeled diagram or a screenshot with obvious content describes well; a dense chart, a small-text infographic, or a low-resolution scan describes poorly. If a fact is critical, don't rely on it living only inside an image; include it in the surrounding text too.
Tables are handled whether they're expressed as text (Markdown, HTML, text-layer PDF) or rendered as images. Text-form tables retrieve more reliably; image tables go through the same image-to-text path and inherit its limitations.
Supported direct-upload formats are listed under [Manage Documents](/manage-documents#supported-file-formats).
## Document, FAQ, or thought?
Documentation is one of three knowledge mechanisms. Choosing the right one matters as much as writing it well.
| Use | When |
| - | - |
| **Document** | Reference material the customer might ask many different questions about. |
| **FAQ** | A common one-line question with a single definitive answer. See [FAQ](/faq). |
| **Thought** | Behavior or process that depends on where the customer is in the flow. See [Thoughts](/thoughts). |
If you find yourself adding the same answer to many FAQs, it probably belongs in a document. If you find yourself writing a document that's really one Q\&A, it probably belongs in an FAQ.
## A quick checklist
Before attaching a document to a flow, run through:
* Does each section stand on its own without the rest of the document?
* Are headings specific enough to describe what's in the section?
* Is terminology consistent with the rest of the library?
* Are acronyms defined where they appear?
* Are there concrete values, steps, and names — not just abstractions?
* Is anything duplicated or contradicted by another document?
* Is the source text-based (not scanned images)?
* Is it current, and is there an owner who will keep it current?
If most of these are "yes", the agent has a good chance of answering correctly from your material.
## Further reading
* [Anthropic — Contextual Retrieval](https://www.anthropic.com/engineering/contextual-retrieval) — the technique used to enrich chunks before embedding.
***
## Related
Upload, sync, and organize source material.
Attach documents and tune retrieval per flow.
Curate short Q\&A pairs.
Query the library directly.