Public Web Embeds (Voice & Chat)
Configure widget embed tokens, enforce allowed domains, and build custom website voice (WebRTC) or headless text chat experiences using Talkar's Public Embed APIs.
Public Web Embeds (Voice & Chat)
Talkar lets you embed any Published workflow directly onto a public website or customer portal in either Browser Voice (WebRTC) or Text Chat mode. Each workflow maintains a single active Embed Token (emb_...) configured from Workflow Settings (Configure Widget) or via /api/v1/workflow/{workflow_id}/embed-token.
1. Dashboard Configuration & Origin Security
From Workflow Settings -> Add to Website -> Configure Widget:
- Widget Type (
voice|chat): Enforced strictly on the backend per token—a token configured forchatrejects WebRTC signaling, and vice versa. Forchatwidgets, you can also configure the workflow's Chat Inactivity Timeout (60–10500seconds, default1800s/ 30 min). - Embed Mode: Choose
floating(corner widget),inline(container mount), orheadless(custom UI wired directly to Talkar's Public Embed APIs below). - Allowed Domains (
allowed_domains): Restrict requests via HTTPOrigin(falling back toReferer). Leave empty to allow any origin, set"*", or supply exact hosts and wildcards (e.g.,app.example.com,*.example.com). Blocked origins receive HTTP403(Domain not allowed). - Usage Caps & Expiry: Token-level
usage_limitand expiration (expires_in_days, default30days on API creation) apply across initialized sessions; usage reservations are atomic at/init.
Managing Tokens via API
Authenticated organization endpoints (X-API-Key or session auth):
POST /api/v1/workflow/{workflow_id}/embed-token— Create or update the workflow's active embed token (allowed_domains,settings,usage_limit,expires_in_days).GET /api/v1/workflow/{workflow_id}/embed-token— Fetch the active token metadata ornull.DELETE /api/v1/workflow/{workflow_id}/embed-token— Deactivate the token immediately.
Context variable sanitization on /init
Visitor metadata passed in context_variables to /api/v1/public/embed/init is sanitized automatically: max 50 keys, max 64-char key names (^[^.\s|{}]+$), total 8192-byte JSON budget, string values capped at 2000 chars, and reserved internal keys stripped (provider, runtime_configuration, etc.). In voice mode, WebRTC offer frames ignore call_context_vars (allow_client_context_vars=false)—always pass context upfront in /init.
2. Public Text Chat Embed Flow
All /api/v1/public/embed/... endpoints handle browser CORS automatically for allowed origins (reflecting Access-Control-Allow-Origin on both success and error responses) and require no API key in the browser.
Step-by-Step Headless Chat Client
- Initialize a 1-hour session (
POST /api/v1/public/embed/init): Inchatmode, Talkar reserves token usage, enforces a 5 req/s init rate limit per token (429), verifies org quota (402), and synchronously generates the Start Call opening greeting inchat_session.turns. - Track
revisionfor optimistic concurrency (POST /messages): Always pass the latestexpected_revision(max message length4000chars; capped at50turns per session and 5 messages/sec per run). If two tabs race and you receive409 Conflict, callGET /api/v1/public/embed/chat/{session_token}to resyncrevisionandturns. - End cleanly without extra quota (
POST /end): Calling/endcompletes the run idempotently, uploads the transcript artifact, and triggers post-call QA and webhooks.
const API = 'https://api.example.com/api/v1/public/embed';
// 1. Start session
const initRes = await fetch(`${API}/init`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: 'emb_your_public_token',
context_variables: { page_url: window.location.href },
}),
});
if (!initRes.ok) throw new Error(`Embed init failed: ${initRes.status}`);
const { session_token, chat_session } = await initRes.json();
let revision: number = chat_session.revision; // includes initial greeting turn
// 2. Send a visitor message with optimistic revision lock
async function sendMessage(text: string): Promise<unknown> {
const res = await fetch(`${API}/chat/${session_token}/messages`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text, expected_revision: revision }),
});
if (res.status === 409) {
// Resync latest revision after a concurrent tab update, then retry once
const syncRes = await fetch(`${API}/chat/${session_token}`);
if (!syncRes.ok) throw new Error(`Resync failed: ${syncRes.status}`);
const sync = await syncRes.json();
revision = sync.revision;
return sendMessage(text);
}
if (!res.ok) throw new Error(`Chat message failed: ${res.status}`);
const updated = await res.json();
revision = updated.revision;
return updated;
}
// 3. End chat when the user closes the widget
const endRes = await fetch(`${API}/chat/${session_token}/end`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ expected_revision: revision }),
});
if (!endRes.ok) throw new Error(`End chat failed: ${endRes.status}`);3. Public Voice (WebRTC) Embed Flow
When building a custom browser voice UI on top of Talkar's WebRTC embed endpoints:
- Inspect widget & TURN config (
GET /api/v1/public/embed/config/{token}): Checkturn_enabledandforce_turn_relay. - Create voice session (
POST /api/v1/public/embed/init): Returns{ session_token, workflow_run_id, widget_type: "voice", config }. (For voice embeds, org concurrency and quota checks execute when the WebRTCofferarrives.) - Fetch TURN ICE servers (
GET /api/v1/public/embed/turn-credentials/{session_token}): Ifturn_enabledistrue, returns{ username, password, ttl, uris }for yourRTCPeerConnectioniceServerslist (503if TURN is unconfigured). - Open WebRTC signaling WebSocket (
WS /api/v1/ws/public/signaling/{session_token}):- Server validates session expiry (
1h), domain allowlist (Origin/Referer), andmode == "smallwebrtc"before accepting (closes with WebSocket code1008on rejection). - Send
{"type": "offer", "payload": { sdp, type: "offer", pc_id }}, trickle ICE via{"type": "ice-candidate", "payload": { pc_id, candidate }}, and optionally send{"type": "dtmf", "payload": { digit }}(0–9,*,#,A–D) or{"type": "renegotiate", ...}. - Listen for server frames:
answer,call-ended(after which the server closes with code1000), anderror(includingconcurrency_limit_exceeded,workflow_run_already_active,concurrency_service_unavailable, or quota error codes).
- Server validates session expiry (
4. Public Embed Error Reference
All public chat and embed session endpoints strictly return allowlist-filtered responses—never exposing prompts, raw stack traces, checkpoint, or internal initial_context / gathered_context.
| Status / Close Code | Endpoints | Meaning |
|---|---|---|
400 | /embed/chat/* | {"detail": "Not a chat session"} (voice token used on chat route) or on /messages: {"detail": {"code": "chat_completed", "message": "Conversation has ended"}} (/end is idempotent on finished chats) |
402 | /embed/init (chat), /messages | "The agent is unavailable right now" (organization wallet or quota exhausted; WS voice sends {"type": "error", "payload": {"error_type", "message"}}) |
403 | /config, /init, /turn-credentials, /embed/chat/* | Token inactive or origin disallowed (/init also enforces expires_at and usage_limit; session routes also enforce 1h session expiry) |
404 | /config, /init, /turn-credentials, /embed/chat/* | Invalid embed token, invalid session_token, or chat session not found |
409 | /chat/{session_token}/messages, /end | {"detail": {"message": "Text chat session revision conflict", "expected_revision": ..., "actual_revision": ...}} |
429 | /embed/init (chat), /messages | Rate limit (5 req/s per token on init or per run on messages) or 50-turn conversation limit reached |
503 | /turn-credentials, /init, /messages | TURN server unconfigured on /turn-credentials, or upstream managed inference unavailable |
WS 1008 | WS /api/v1/ws/public/signaling/{session_token} | Invalid/expired session, non-voice session, or Origin/Referer rejected before handshake |
MCP & Third-Party Integrations
Connect external Model Context Protocol (MCP) servers over Streamable HTTP with tool allowlists, namespacing, and Talkar's hosted inbound `/api/v1/mcp` server.
Talkar Service API Reference
Programmatically launch outbound calls, poll or SSE-stream live transcripts, read wallet/transactions, upload S3 files, integrate public web embeds, and call Talkar Automation APIs.