---
title: "Create an authenticated LiveKit browser-test session for one hosted agent"
method: POST
path: "/v1/agents/{agent_id}/browser-sessions"
---

# Create an authenticated LiveKit browser-test session for one hosted agent

`POST /v1/agents/{agent_id}/browser-sessions`

## Request

- Base URL: `https://api.skysay.ai`
- URL: `https://api.skysay.ai/v1/agents/{agent_id}/browser-sessions`
- Auth: none declared

Workspace-authenticated only. Does not use the anonymous homepage demo budget. New sessions reserve eligible browser-only welcome credit or purchased funds and settle actual component usage; no carrier charge applies. The existing session limit is 180 seconds. Historical zero-charge snapshots remain unchanged. The selected snapshot is published or a validated draft overlay. A draft overlay naming an unknown, retired, or language-incompatible selection is rejected with a plain 400 before this point, as before. Beyond that, the resolved realtime configuration -- the agent's stack merged with any draft overlay -- is checked for runnability before anything is reserved; a config the voice worker would refuse before building media (missing prompt/first message, missing provider/model/voice, or an unsupported language) is refused here instead of reaching the worker.

## Path parameters

- `agent_id` string, required

## Request body

- object
  - `draft` object: Only read when snapshot is 'draft'. `first_message`, `instructions` and `language` apply to an agent without a selected language set (a published set pins the per-locale greeting, prompt and language). `stack` applies to every draft test and names its conversation engine in `stack.voice_frontend` ('cascade' or 'gpt_live') plus that engine's own fields: for cascade the `transcriber`, `model` and `voice` selections (`{provider, model, voice_id}`; leaving GPT-Live needs all three); for GPT-Live the `voice` (`{provider: 'openai', model: 'gpt-live-1', voice_id}`) and `model` (`{provider: 'openai', model: <backend>}`) -- no transcriber, a cascade one riding along is refused. A stack with no `voice_frontend` is a partial cascade overlay on the stored engine. A draft stack is refused while Follow the caller is published for the agent.
    - `first_message` string
    - `instructions` string
    - `language` string
    - `stack` object
      - `model` object
      - `transcriber` object
      - `voice` object
      - `voice_frontend` 'cascade' | 'gpt_live'
  - `organization_id` string, required
  - `project_id` string, required
  - `snapshot` 'published' | 'draft'
  - `test_values` object: Values for the agent's declared variables, for this test call only. Built-ins (contact.*, call.*, campaign.*) are not sent. Refused like a call's values: 400 with reason one of call_variables_missing, call_variables_invalid, call_variables_over_budget, workflow_binding_failed, schema_pair_mismatch, per_call_text_on_workflow, agent_not_published, keypad_value_not_dialable, keypad_value_in_text, and field / where naming the variable or line (never a value).

## Response `201`

Reservation and dispatch metadata for a LiveKit join token

## Other responses

- `400`: Either a plain {error, message} (an invalid draft overlay selection, unchanged from before) or, when the resolved config passes overlay validation but is still not runnable: {error: 'realtime_config_not_runnable', reason: <code>, blockers: [{code, scope, detail}]}. Codes reuse the same admission vocabulary already returned by the Agents/Numbers dashboard reads (e.g. voice_id_missing, system_prompt_missing, first_message_missing, language_not_runnable, llm_model_missing, delivery_profile_invalid). No room or reservation is created either way.

---

[API](https://skmtc.dev/skysay/apis/skysay-api.md) · [All operations](https://skmtc.dev/skysay/apis/skysay-api/llms.txt) · [OpenAPI document](https://skmtc.dev/skysay/apis/skysay-api/revisions/148c7e111260?raw)
