Skip to main content

Overview

A widget is an embeddable voice call entry point. You create a widget, configure its appearance and linked assistant, then embed it in your product. When a user clicks the call button, your frontend calls POST /v1/widgets/create-call to get a WebSocket URL and starts the audio session. Required scopes: widgets:read (read), widgets:write (create/update/delete/call)

POST /v1/widgets

Creates a new widget for your organization. Pass assistantId to attach an existing agent at creation time — if a widget already exists for that agent, the existing widget is returned instead of creating a duplicate. Omit it to create an unattached widget you configure later via PATCH /v1/widgets/{id}.
Announcer agents (see Agents → Announcer agents) can’t be attached to a widget — they’re one-way broadcast agents with no conversational voice engine. Passing an announcer agent’s id as assistantId here (or in PATCH /v1/widgets/{id}) returns a 400.
201 Created
Common errors: 400 assistantId belongs to an announcer agent · 403 missing widgets:write scope

GET /v1/widgets

Lists all widgets for your organization.

200 OK

Common status codes

  • 200 success
  • 403 missing widgets:read
  • 500 server error

GET /v1/widgets/{id}

Returns a single widget by ID.

200 OK

Common status codes

  • 200 success
  • 403 missing widgets:read
  • 404 widget not found (including a widget that belongs to a different organization)
  • 500 server error

PATCH /v1/widgets/{id}

Updates a widget’s appearance, assistant, and allowed origins. This is a full replace, not a partial patch — every field below is required on every call, even to change just one of them. Unrecognized fields in the payload are ignored rather than causing an error. Setting water_mark_enabled to false requires an active paid subscription on the organization — this returns 403 for organizations on the Free plan or with no active subscription. Most fields are plain CSS-style values (hex colors, pixel radii, button labels) and are self-explanatory from the example below. Two worth calling out:
  • allowed_origins — an array of origins (scheme + host, e.g. https://app.example.com) permitted to embed and call this widget from the browser. Requests from any other origin are rejected.
  • terms_and_condition_content — free text shown when terms_and_condition is true. It isn’t validated server-side, so an empty or missing value is accepted even when terms_and_condition is true — it’s on you to supply real copy in that case.
Common errors: 400 validation error · 403 missing widgets:write scope, or organization is not on a paid plan (when disabling water_mark_enabled) · 404 widget not found

POST /v1/widgets/create-call

Creates a call session for a widget. Call this from your server when a user clicks the call button in your UI.
The widget’s allowed_origins (set via PATCH /v1/widgets/{id}) is checked against this request’s Origin header, not the end user’s browser origin. A typical server-side HTTP call doesn’t send an Origin header at all, which fails this check — so when calling this endpoint from your backend, explicitly set an Origin header matching one of the widget’s allowed_origins, or the request is rejected with 400 Domain is not supported.
201 Created
Pass gateway.url to your browser client to open the WebSocket connection. The call_id can be used later to retrieve the transcript via GET /v1/calls/{id}/transcripts. Common errors: 400 invalid payload; widget has no assistant attached (attach one via PATCH /v1/widgets/{id} first); or the Origin header doesn’t match the widget’s allowed_origins · 403 missing widgets:write scope · 404 widget not found

DELETE /v1/widgets/{id}

Permanently deletes a widget.
Common errors: 403 missing widgets:write scope · 404 widget not found