Skip to content

Live Voice API

What this is

Three HTTP endpoints under /api/live that back the ComStack live voice agent. The browser authenticates, opens a WebSocket connection to the voice AI service, and forwards tool call events back through the server. The server handles session provisioning, tool dispatch, multilingual label resolution, and live call transfer to a team member.

Base URL: https://api.comstack.ai


Authentication

All three endpoints require the same two headers:

HeaderValue
AuthorizationBearer <Firebase ID Token> — from getIdToken() on the signed-in Firebase user
x-project-idYour project’s Firestore document ID

This auth model is separate from the MCP API key auth used by the /mcp endpoint.

Error responses:

StatusCause
401Missing or invalid Authorization header
400Missing x-project-id header

POST /api/live/session

Mints an ephemeral voice session token. Validates that the user is a project member, that the voice module is enabled, and that the daily session quota has not been reached.

Request

No body required. Auth headers only.

Response 200

{
"token": "projects/.../ephemeralTokens/...",
"greeting": "Hi! How can I help you today?",
"voice": "Aoede"
}
FieldTypeDescription
tokenstringEphemeral voice session token. Valid for 30 minutes; single-use.
greetingstringOpening line for the agent to speak at session start. Sourced from the project’s live agent configuration. Empty string if not configured.
voicestringVoice name sourced from project configuration.

Guard conditions — 403

ConditionError
Voice module disabled"Voice web agent not enabled for this project"
User not provisioned"This user has not been provisioned. Contact a manager."
User not a project member"User is not a member of this project"

Session quota — 429

The daily session limit is enforced atomically before the token is minted. When the per-user daily count reaches the plan limit, the call returns 429 and no token is issued:

{ "error": "Daily live-session limit reached (5/day). Try again tomorrow or upgrade your plan." }

The counter is per user per UTC day. Concurrent session starts cannot burst past the limit — the reservation and mint happen in a single transaction. See Plans and Quotas for limit values by plan.


POST /api/live/session/resume

Mints a fresh token for reconnecting after a WebSocket drop (GoAway, error 1007, or similar). Functionally identical to POST /api/live/session.

Clear the session’s resume handle before calling this endpoint so the new token starts a clean session rather than attempting to resume the broken one.


POST /api/live/tools/execute

The voice AI dispatches tool calls during a session. The browser receives each toolCall event from the WebSocket and forwards it to this endpoint. All tools respond synchronously.

Request

{
"tool_name": "update_profile",
"args": {
"first_name": "María",
"phone": "+34 611 22 33 44"
}
}
FieldRequiredDescription
tool_nameyesName of the tool to execute. Standard set: update_profile, ask, answer, transfer_to_manager. Feature-gated set (when onboarding module is enabled on the project): search_company, select_company, run_extraction, set_field, confirm.
argsnoTool arguments. Defaults to {} if absent.

Response 200

{
"result": "Language changed to Spanish. Continue speaking in Spanish from now on.",
"widget": {
"type": "card",
"card_id": "profile_card",
"template_id": "profile_v1",
"dir": "ltr",
"data": {
"first_name": "María",
"last_name": null,
"pronoun": "unspecified",
"phone": "+34611223344",
"contact_email": null,
"language": "es-ES",
"language_label": "Spanish"
},
"labels": {
"profile": "Perfil",
"first_name": "Nombre",
"pronoun": "Pronombre",
"email": "Correo",
"phone": "Teléfono",
"language": "Idioma"
},
"pronoun_labels": {
"she_her": "Ella",
"he_him": "Él",
"they_them": "Elle",
"unspecified": "No definido"
}
}
}
FieldDescription
resultText for the agent to speak aloud. Language-change results include the new language name and an instruction to continue in it.
widgetCard payload to render on screen. Present when a profile card should appear or update. card_id: "profile_card" is stable — always replaces in place.
widget.dirText direction: "ltr" or "rtl" for Arabic, Hebrew, Farsi, Urdu, and other RTL languages.
widget.labelsServer-resolved translated labels for card fields. Falls back to English if no cached translation is available.
widget.pronoun_labelsServer-resolved translated pronoun display values. Falls back to English if no cached translation.

update_profile — field handling

ArgNormalization
first_name / last_nameTrimmed; empty string → null
pronounFuzzy-mapped — accepts natural forms like "she", "he/him", "non-binary"
phoneParsed to E.164 format; country inferred from user’s language setting
contact_emailLowercased and trimmed; must contain @
languageMatched against language name map or validated as BCP-47 directly. When language changes, the two widget-critical translation scopes are awaited before the response returns; subsequent switches to the same language are instant cache hits.

Calling update_profile with no args returns the current profile without writing — used to surface the profile card on demand.

transfer_to_manager

Bridges the caller to a human team member:

  1. The caller is placed in a private conference room on brief hold.
  2. The server initiates an outbound call to the project’s configured manager phone number.
  3. Once the manager answers, they join the same conference.

No arguments required. The caller goes from the website to a live team member in seconds. Outbound calls require phone permissions to be enabled for the destination country.

Onboarding tools (feature-gated)

Available only on projects where the onboarding module is enabled. Each tool mutates the visitor’s active onboarding session.

ToolArgsEffect
search_companycountry (ISO-3166-1 alpha-2), queryBusiness registry lookup; returns up to 5 candidates.
select_companycountry, registry_id?, place_id?, business_url?Stores the selected business identity on the session. Clears any previously extracted profile if the identity changed.
run_extraction(none)Full grounded extraction over the selected company. Writes the resulting profile to the session.
set_fieldpath, valueInline edit on an allowlisted session field path. Allowed paths: voice, greeting_draft, primary_language, brand_tone, service_area, opening_hours, summary, industry, target_audience, intent, languages, products_services, unique_selling_points.
confirm(none)Marks the onboarding brief as confirmed.

All tools return { result: string } where result is the natural sentence the agent speaks.

Errors

StatusCause
400tool_name missing from request body
500Tool dispatch threw an unexpected error

Live agent placement

Where the voice agent appears on the published site is controlled by the live_agent_placement setting in your project’s site configuration:

PATCH /api/projects/:pid/settings/site
{
"live_agent_placement": "widget"
}
ValuePlacement
homepageAgent embedded on the homepage
destination_pageAgent served at a dedicated slug (live_agent_slug)
widgetFloating widget on all pages
modalFull-screen modal
noneAgent disabled on the site

In destination_page mode, a page whose slug collides with live_agent_slug is rejected at create/update time. The slug automatically unlocks when the placement mode changes away from destination_page.


Widget labels

The browser has no hardcoded translation maps. All card labels and pronoun translations are resolved server-side from the project’s translation data and sent in the widget payload. The browser only maintains English fallback constants for legacy responses.

When a user switches language for the first time, the server awaits translation before responding — approximately 1–2 seconds. Subsequent switches to the same language return immediately from cache.


Common errors

401 Unauthorized — the Firebase ID Token is expired or invalid. Re-sign the user in and call getIdToken() to get a fresh token.

403 Voice web agent not enabled — the voice module is disabled on this project. Check the project’s module settings or upgrade the plan.

403 User not provisioned — the signed-in user has not been added to this project. A project manager must provision the user account first.

429 Daily live-session limit reached — the per-user daily quota is exhausted. The limit resets at UTC midnight. The error message includes the limit value. Upgrade the plan for a higher quota.

400 tool_name missing — the /tools/execute request body is missing the tool_name field.


Last updated: