Skip to main content
Use this when you want to embed a scenario on a third-party site and either the scenario is private, or you want to pass per-user identity, or you want to lock the iframe to specific origins. If your scenario is public and you don’t need any of the above, you can skip this and use the tokenless URL from the Studio Share modal — see Embedding a scenario on your website.

When to use this endpoint

Tokens are short-lived (default 10 min, max 30 min) and origin-locked. Mint one server-side per session so your wai_ key never reaches the browser.

One-call DX

The response gives you the token, the fully formed iframe URL, and a copy-pasteable <iframe> snippet. No client-side URL assembly.
Response:
Drop iframe_html into your page server-rendered and you’re done.

Prerequisites

Before this endpoint works for a scenario:
  1. Embedding must be enabled on the scenario (embed_enabled: true). Toggle it in the Studio Share modal or via the Scenarios API.
  2. Allowed origins must be set on the scenario (embed_allowed_origins) so the iframe is only renderable from your domains. The token won’t validate against any origin that isn’t on this list.
If either is missing the endpoint returns 403.

Request body

string
required
UUID of the scenario to embed. Must be owned by the caller’s membership and have embed_enabled: true.
string
End-user identity. The token’s identity key. Resolves to a per-creator participant record so the same end user across multiple meetings is recognised as one identity (enables cross-session participant memory, accurate analytics, and a coherent dashboard view). Also resolves the {{USER_EMAIL}} personalization token in the meeting script. Omit for a fully anonymous embed — the session still runs, but there’s no persistent identity and no cross-meeting memory.
string
UUID of a participant you pre-created via POST /v1/participants (advanced). Use when you want to control the participant record explicitly — for example, building a roster ahead of time. Wins over email if both are sent. Must belong to the scenario’s organisation.
string
Metadata only — not used for identity resolution. Your local user ID on the partner side. Stored on the participant record as external_ref so you can reconcile our participant rows against your own user table. Send it alongside email; on its own (no email) it has no identity effect and the session runs anonymously. Max 128 chars.
string
Display name shown in the meeting UI (e.g., on the join screen). Also resolves the {{USER_FIRST_NAME}} and {{USER_NAME}} personalization tokens in the meeting script. Max 80 chars.
string[]
Per-token origin allowlist. Must be a subset of the scenario’s embed_allowed_origins. Use this when one scenario is embedded across multiple sites and you want a token scoped to one of them. Each entry must be a bare HTTPS origin like https://partner.example.
integer
Token lifetime. Range 301800. Default 600 (10 min).
string
Which iframe route the snippet points at. One of:
  • button (default) — floating start button that opens the meeting in an overlay
  • inline — full meeting UI inline in the page
  • avatar-assist — floating avatar widget in the corner
string | number
Iframe width on iframe_html. CSS string ("100%", "640px", "50vw") or a positive px number. Default "100%".
string | number
Iframe height on iframe_html. Same shape as width. Default 640.

Response

string
Signed JWT. Treat as a credential — short-lived but powerful inside its TTL.
integer
Unix seconds at which the token stops validating.
string
Fully formed embed URL with ?t=<token> baked in. Use this if you want to construct your own iframe.
string
Copy-paste-ready <iframe> snippet with the URL, sizing, and the WebRTC allow attributes already set.

Variants

Button

Floating start button that opens the meeting in a modal overlay. Default. Best when you’re adding embed to an existing page without layout changes.

Inline

Full meeting UI rendered inline. Best for training portals, LMS, or dedicated meeting pages where the embed is the main content.

Avatar Assist

Compact avatar widget in the corner. Best for support bots and onboarding nudges.

Token refresh

Tokens expire (default 10 min). If the iframe is loaded but the user hasn’t started the session yet when the token expires, the session start will be rejected. Two ways to handle this in practice:
  1. Mint on demand. Generate the token at the moment the page renders, not ahead of time. Server-render the iframe_html. Don’t cache the response.
  2. Mint a fresh token client-side just before opening the modal. If you’re using variant: "button" and the user might sit on the page for a while, refresh the token via an AJAX hit to your own backend (which proxies to this endpoint) right before opening the iframe.
If you need a longer TTL, raise ttl_seconds (max 1800 = 30 min). Going much higher is intentionally not supported — leaked tokens should go stale fast.

Origin lock

The token’s claims include the origin allowlist, and the iframe enforces it at session start. A leaked token presented from an origin not on the list is rejected.
If you omit allowed_origins, the token inherits the scenario’s full embed_allowed_origins list.
The iframe needs allow="camera; microphone; autoplay" to function. The iframe_html field has this set already; if you build your own iframe, copy these attributes verbatim. Your site must also be served over HTTPS — browsers block mic/camera on non-secure origins.

Quick recipes

Node.js / Express

Python / FastAPI

Errors