# Training material Source: https://docs.dialai.ca/agent-training Short videos and the Agent handbook — set the AI agent's hours and holidays, and plan your team's coverage around it Learn how to set when the AI agent answers, and how to plan your team around it. 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. ``` Replace the URL with the one from the Generate tab, and adjust width/height to fit your page. ### Toggling on a button click For a "click to open chat" pattern, mount/unmount the iframe on demand. Chat context is preserved between iframe reloads as long as the visitor's session cookie is intact. ```js theme={null} document.getElementById("toggle-chat").addEventListener("click", () => { const id = "dial-ai-chat"; const existing = document.getElementById(id); if (existing) { existing.remove(); return; } const iframe = document.createElement("iframe"); iframe.id = id; iframe.src = "https://your-instance.dialai.ca/your-tenant/chat/00000000-0000-0000-0000-000000000000"; iframe.width = "500"; iframe.height = "500"; document.getElementById("root").append(iframe); }); ``` ## iframe vs script tag | Use iframe when… | Use [script tag](/script-tag-integration) when… | | - | - | | You want chat embedded inline in your layout. | You want a floating button + modal. | | You're OK with iframe-sandbox limitations. | You want native styling and a smaller bundle footprint. | | You're embedding inside another iframe-friendly host. | You're embedding inside a SPA where DOM control is straightforward. | ## CSP and X-Frame-Options The chat URL ships with a `Content-Security-Policy-Report-Only` header that allows `frame-ancestors 'self' https://*.hansencx.com`. The report-only policy means the platform logs violations but doesn't block — if your embed origin is outside the allow-list you'll see violation reports in browser dev tools, not a blocked iframe. If you need your embed origin allowed in an enforced policy, contact your account representative to extend the platform's CSP. Your embedding page does not need any special headers unless your own CSP restricts iframe sources — in that case, allow `https://your-instance.dialai.ca` in your page's `frame-src` directive. ## Tips * **Use a stable Version** when embedding into production. Tracking the draft means the chat behavior can change at any time without you knowing. * **Set Link Name** before you copy the URL. It shows up in [Conversations](/conversations) and makes it much easier to attribute traffic. * **Test the embed on a staging URL** before production — some browsers and corporate firewalls block third-party iframes even when CSP allows them. *** ## Related The new way to put chat on a website. Floating button + modal instead of inline iframe. Skip the widget entirely and use the REST API. How to pass verified user identity into the chat. Manage legacy web chats. # Inbox Source: https://docs.dialai.ca/inbox Monitor and take over conversations that need human handling Inbox in light mode Inbox in dark mode The **Inbox** is built for human agents who handle conversations the AI can't (or shouldn't) resolve on its own. When a conversation is queued for human help — by the AI itself, by a supervisor, or by a routing rule — it shows up here, waiting for a human to pick it up. Pair the Inbox with [Live View](/live-view) for real-time monitoring of AI-handled conversations, and with [Conversations](/conversations) for the searchable archive after a conversation closes. ## Accessing the Inbox Navigate to **Monitor > Inbox** in the left sidebar. There are two views: * **Inbox** (default) — every conversation in your queue, routed by skill match. * **Inbox / Personal** — a configurable per-agent view. Set this up under **Configure Inbox** in the top bar. ## Audio configuration (Agent Leg status) The top-left of the Inbox shows your **Agent Leg** indicator — your audio connection's readiness for voice calls. * **Connected** — you're ready to receive voice calls. * **Disconnected** — click to reconnect. The system uses your configured phone number from **Settings > Personal Configuration**, or opens a modal to set up web audio with your headset. * **Ringing** — a queued voice call is being routed to you. For chat and email conversations, no audio leg is needed. ## Status management Use the **Status** dropdown in the top bar to control your availability: * **Available** — eligible for new conversations. * **Busy** or **Offline** — conversations won't route to you. Skill-based conversations that are already assigned to you are returned to the queue for reassignment; conversations that were routed directly to you (agent-specific) remain assigned and are not re-routed. ## How a conversation reaches you The AI agent decides it needs human help — based on the flow logic, the customer's request, or a function call — and queues the conversation with one or more **Skills** describing what's needed (e.g., Billing, Spanish, Fraud Assistance). Skills are managed under **Settings > Operations > Skills**. The Automatic Call Distributor picks an **Available** agent whose configured skills match. Chat and email caps can be adjusted from the Inbox top bar or under **Settings > Personal Configuration**. Voice calls are capped at one per agent at a time and cannot be changed. When a conversation is routed to you, you can **Accept** it to take it on, or **Reject** it back into the ACD for reassignment. ## Taking over * **Voice calls** — your phone or headset rings (per your selected audio method). Answer to take control. * **Chats / emails** — open directly inside the Inbox for real-time messaging. The conversation panel shows the full context: the transcript so far, sentiment, the flow the AI was running, and any parameters the AI captured before handing off. ## Ending a conversation After you resolve the issue: 1. **Hang up** (voice) or click **End** (chat/email). 2. The conversation enters a **Wrap-up** state for any final notes. 3. Once wrap-up closes, you're eligible for new conversations again. ## Callbacks When every agent is busy, the AI can offer the caller a **call back** instead of leaving them on hold. The caller keeps their place and hangs up, and the system rings them back the moment an agent frees up, with an estimated wait time. After hours, callers join a **callbacks list** your team works through the next morning. Callbacks queue in light mode Callbacks queue in dark mode Work callbacks from **Monitor > Callbacks**: * **Callbacks** — the queue of customers waiting for a call back, with their reason, priority, and how long they have waited. Click **Get next** to take the top one, or pin specific queues to yourself. * **Virtual hold** — a live view of callers waiting for the next free agent, whom the system calls back automatically. *** ## Related Watch AI-handled conversations in real time. Search past conversations. Define and manage routing skills. Set your phone, status, and skill assignments. # Passing Context Securely Source: https://docs.dialai.ca/integration-context How to pass user identity and other context into chat sessions without allowing impersonation. This page describes how to pass context into the legacy web chat: chat links from the **Web (Legacy)** tab of **Points of Contact**, with the [iframe](/iframe-integration) or the [script tag](/script-tag-integration). Chat links still work for now, but they are deprecated. For a new site, use [Web Widgets](/web-widgets) with [signed-in visitors](/web-widget-sign-in). ## Signed-in visitors replace these approaches A web widget with sign-in replaces all three approaches on this page: | Approach on this page | With a web widget | | - | - | | [External JWT with public key verification](#approach-1-external-jwt-with-public-key-verification) | Add your identity provider as a sign-in provider of the widget, with its **JWKS URL** or its public key. | | [Server-side token verification](#approach-2-server-side-token-verification) | Your backend checks the session of the customer and signs a short token for the widget, with a shared secret or its own key. | | [Backend-created chat links](#approach-3-backend-created-chat-links-with-baked-in-context) | No link for each customer. The token carries the values, and the widget maps its claims to context parameters. | In each case, your page gives the token to the widget through the `identity` function. The platform checks the token each time the session starts or refreshes. See [Signed-in visitors](/web-widget-sign-in). The rest of this page applies to chat links only. *** When embedding Dial AI into your application, you often need to pass context — such as the logged-in user's ID, account number, or role — into the chat session so that functions can act on behalf of that user. Because the widget runs client-side, any context sent directly from the browser can be forged. A malicious user could change their `userId` to someone else's and impersonate them. This page covers three approaches to passing context securely, each suited to different integration architectures. ## The Problem Consider a script-tag integration where you pass a user ID as an extra parameter: ```js theme={null} // DON'T DO THIS — the user can change "user-123" to any value window.renderModal("dial-ai-button", { chatId: "00000000-0000-0000-0000-000000000000", backendUrl: "https://your-instance.dialai.ca", iconUrl: "/icon.svg", extraInternalParameters: { userId: "user-123" } }); ``` Because this code runs in the user's browser, nothing prevents them from opening DevTools and changing `"user-123"` to `"user-456"`. Any downstream function that trusts this value is now operating on the wrong user's data. All three approaches below solve this by ensuring user identity is verified server-side before it reaches your flow. *** ## Approach 1: External JWT with Public Key Verification If your application already issues JWTs to authenticated users (e.g. via an identity provider like Auth0, Cognito, or Keycloak), Dial AI can validate those tokens directly and extract claims from them. ### How It Works 1. Your identity provider issues a signed JWT to the user when they log in 2. The user's browser passes this JWT to Dial AI when creating a chat session 3. Dial AI verifies the JWT signature against your provider's public keys (via a JWKS endpoint) 4. Dial AI checks the issuer claim matches your configured issuer 5. Verified claims (e.g. `sub`, `accountId`) are extracted and made available as internal parameters Because the JWT is cryptographically signed, the user cannot modify the claims without invalidating the signature. ### Setup To configure external JWT verification, provide Dial AI with: * **JWKS URL**: The endpoint where your identity provider publishes its public keys (e.g. `https://your-idp.com/.well-known/jwks.json`) * **Issuer**: The expected `iss` claim in the JWT (e.g. `https://your-idp.com/`) * **Tenant**: Which Dial AI tenant this JWT configuration applies to Once configured, users authenticate to Dial AI by passing their JWT as a Bearer token. Dial AI verifies the signature and issuer, then makes the JWT's claims available to your flow. ### When to Use This * You already have an identity provider that issues JWTs with a JWKS endpoint * You want a zero-backend-work integration — the browser can pass the token directly * You need access to multiple claims from the token (e.g. user ID, roles, email) *** ## Approach 2: Server-Side Token Verification If your users authenticate with tokens that aren't JWTs, or you need to verify additional state beyond what's in a token (e.g. checking that an account is still active), you can verify the user's identity via a server-side request before passing context to Dial AI. ### How It Works 1. The user logs in to your application and receives a session token 2. When starting a chat, your frontend sends the session token to **your backend** 3. Your backend validates the token against your system of record (database, auth service, etc.) 4. Your backend creates a chat session via the Dial AI API, passing verified context as `extraInternalParams` 5. The chat link or session ID is returned to the frontend The user never passes their own identity to Dial AI — your backend does, after confirming who they are. ### Example Flow ``` Browser Your Backend Dial AI │ │ │ │─── start chat ────────────►│ │ │ (session token) │ │ │ │── verify token ──► │ │ │◄── user: alice ─── │ │ │ │ │ │── POST /api/chat/link ───►│ │ │ { extraInternalParams: │ │ │ { userId: "alice" } } │ │ │◄── chat link UUID ────────│ │ │ │ │◄── chat link UUID ────────│ │ │ │ │ │── open chat (X-DialAi-Chat-Link: Bearer ) ─────►│ ``` ### When to Use This * Your auth system doesn't use JWTs, or uses opaque tokens * You need to check live state (account status, permissions) at chat-creation time * You want full control over what context is passed to Dial AI *** ## Approach 3: Backend-Created Chat Links with Baked-In Context Dial AI supports creating chat links via API with context permanently embedded in them. This is especially useful for short-lived, user-specific sessions. ### How It Works 1. Your backend authenticates the user through your own auth system 2. Your backend calls the Dial AI API to create a chat link, including verified user context in `extraInternalParams` 3. The chat link UUID is returned to the frontend 4. The frontend uses this link to open the chat — the baked-in context is automatically attached to every conversation created with this link The context is stored server-side in Dial AI and cannot be modified by the client. ### Permanent Chat Links Create a chat link with context that persists until explicitly deleted: ``` POST /api/chat/link Authorization: Bearer { "flowId": "your-flow-id", "name": "Support chat for alice", "extraInternalParams": { "userId": "alice", "accountTier": "premium" }, "settableInternalParams": ["preferredLanguage"] } ``` * **`extraInternalParams`**: Context baked into the link. Every chat created with this link will have these values as internal parameters. The client cannot override them. * **`settableInternalParams`**: Parameters the client is allowed to set when creating a chat. Use this for non-sensitive context like UI preferences. If a client attempts to set a parameter not in this list, the request is rejected. > If a key appears in both `extraInternalParams` and `settableInternalParams`, the client-provided value will take precedence over the baked-in value. This is useful for providing overridable defaults, but be careful not to put trusted identity values (like `userId`) in `settableInternalParams` — the client would be able to override them. ### Temporary Chat Links with JWT Claim Extraction For short-lived sessions, create a temporary chat link that automatically extracts claims from the caller's JWT: ``` POST /api/v2/chat/link/temporary Authorization: Bearer { "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 Dialai dashboard in light mode Dialai dashboard in dark mode 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.