Browser Sessions
Browser mint endpoint — Origin allowlist auth.
POST /v1/browser-sessions
Called by the SDK for browser embeds when you
pass experienceId. Auth is the page Origin against your allowlist —
not an API key in the browser.
Request
POST https://api.liforma.ai/v1/browser-sessions
Origin: https://your-app.com
Idempotency-Key: optional-unique-key
Content-Type: application/json
{
"experienceId": "exp_T0I7ACMQLBMPG6K",
"locale": "en-GB",
"secondaryLocale": "fr-FR",
"mode": "conversation",
"speechInputMode": "auto",
"speechOnly": false
} Response 201
SessionLaunchResponse: session plus opaque launch. Header: Cache-Control: no-store, private. Dual sessions also echo session.secondaryLocale when resolved.
Parameters
| Field | Required | Description |
|---|---|---|
experienceId | Yes | Experience to launch |
locale | No | Primary / user language (BCP 47). SDK defaults to navigator.language when omitted. |
secondaryLocale | No* | Dual: paired / learning language (BCP 47). Required when the creator left the paired
axis as Match; ignored when Fixed. Non-dual: when conversation is Match, immerses the
session in this language (wins over browser/locale); ignored when Fixed. |
learningLocale | No | Alias of secondaryLocale — prefer for language-learning apps (tutors and
roleplay). Must not disagree with secondaryLocale when both are set. |
mode | No | conversation or presenter |
speechInputMode | No | auto, manual, or off |
speechOnly | No | When true, voice-only session without avatar/location assets |
* Language-learning apps can pass the same learningLocale (or secondaryLocale) for tutors and roleplay. Dual tutors use it as the learning
axis (clip / v2a pipeline); non-dual roleplay immerses conversation and voice in that
language when Studio left Match open (plain / v2b). Creator Fixed still wins.
Player chrome (startButton, closeButton, returnUrl, fit) is configured via SDK attach / component props — not on this
request.
Checks
Originheader required- Browser embeds must be enabled for the project
- Origin must be on the project allowlist
- Experience must have a published revision
- Quota and rate limits apply
CORS
api.liforma.ai returns CORS headers for the requesting Origin, including Idempotency-Key on preflight. CORS is not authorization — Origin allowlisting
happens on the POST. The SDK calls this endpoint directly from the browser.
Optional Idempotency-Key (max 256 characters; longer values → 400 IDEMPOTENCY_KEY_INVALID): same key + same body replays the prior launch; same
key + different body → 409 IDEMPOTENCY_CONFLICT; same key still pending → 409 IDEMPOTENCY_IN_PROGRESS with Retry-After: 1. Branch on error.code, not HTTP 409 alone.
Machine-readable contract: /openapi/sessions.json.
Example
curl -X POST https://api.liforma.ai/v1/browser-sessions \
-H "Origin: https://your-app.com" \
-H "Content-Type: application/json" \
-d '{"experienceId": "exp_T0I7ACMQLBMPG6K"}'