Skip to main content

Realtime API

sessions/start is the single call you make to start a realtime conversation. It creates the room, brings in the AI agent (and an avatar, if you want one), and returns everything your app needs to join: a room name, a JWT access token, and the server URL.

Endpoint​

POST https://api.lookalike.com/v1/sessions/start

Request​

Send a JSON body. Every field is optional — an empty body {} starts a default session. To start an avatar session you only need identity_id: supplying it turns the avatar on automatically, so you don't also have to set avatar_enabled.

FieldTypeDescription
identity_idstringOnboarded persona/identity id to render as the talking-head avatar. Supplying it implies avatar_enabled: true.
avatar_enabledbooleanSet to true to add a talking-head avatar video. Implied when identity_id is set.
languagestringPer-session conversation language: auto, en, es, pl, or uk. Omit it to use the identity's stored language.
visual_awarenessbooleanLet the agent see the visitor: while they speak, frames from their camera accompany their words as image input, so the Lookalike can react to what it sees. Omit it for the account default (currently on for every identity-backed session), or send false to opt the session out. The response carries the effective value.
form_factorstringThe visitor's device class: phone or desktop. The avatar video is rendered in a shape suited to it: portrait for phone, and landscape for desktop where landscape video is enabled (until then, desktop sessions get the default portrait video). Omit it to get the default shape. Any other value returns 422 before the room is created.

Everything else about the persona is resolved from the identity itself: which renderer serves it, which image it wears, and which cloned voice it speaks with. There is no field to override any of them, and none is needed - sending a different identity_id changes all three together.

Conversation language​

The effective conversation language is selected in this order:

  1. language in POST /v1/sessions/start
  2. the language stored on the identity
  3. en, when the call supplies no identity to read a language from

Passing "language": "auto" is an explicit override: the greeting is English and later replies follow the visitor's detected language. A session override never changes the identity - read it back with GET /v1/identities/{identity_id} and it is still whatever you stored.

{ "identity_id": "test-identity-03d39af9", "language": "es" }

Swap es for pl, uk, en, or auto. A pinned language is a hard constraint: the agent answers only in it, even when the visitor switches. Anything outside the five values returns 422 before the room is created.

Every mode except en needs an identity with an ElevenLabs voice, and that includes auto - letting the visitor pick the language is as multilingual a demand as pinning one. Without such a voice the API returns 422 rather than falling back to an English-only voice that would read the words with the wrong phonemes.

Example​

The minimal call — just the persona id:

curl -X POST https://api.lookalike.com/v1/sessions/start \
-H "Authorization: Bearer $LOOKALIKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"identity_id": "test-identity-03d39af9"}'

Response​

200 OK:

{
"room_name": "room-user-001-6014c7ef",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"livekit_url": "wss://your-livekit-server",
"dispatch_id": "AD_xxxxxxxxxxxx",
"user": { "id": "acct_ab12cd34" },
"created_at": "2026-06-17T09:10:27.994123+00:00",
"visual_awareness": true
}

The three fields you need to join are room_name, token, and livekit_url. The token already encodes the room and your identity — you don't sign or mint anything yourself.

visual_awareness tells your client whether this session's agent will use the visitor's camera. When it is true, offer a camera control and publish an ordinary camera track when the visitor turns it on (the agent samples it only while they speak). When it is false, don't offer one — frames would be ignored.

Errors​

StatusMeaning
401 UnauthorizedMissing or invalid API key.
422 Unprocessable EntityThe request body is malformed.
500 Internal Server ErrorSomething went wrong on our side — retry shortly.

Join the room​

The token is a standard LiveKit access token. Connect with any LiveKit client SDK using livekit_url + token; the room is already set up and the agent is on its way in.

import { Room, RoomEvent, Track } from 'livekit-client';

// livekitUrl and token come from the sessions/start response
const room = new Room();

room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
if (track.kind === Track.Kind.Video) {
// attach the avatar video track to a view element
document.getElementById('avatar').appendChild(track.attach());
} else if (track.kind === Track.Kind.Audio) {
// play the agent audio track
document.body.appendChild(track.attach());
}
});

await room.connect(livekitUrl, token);

// enable the local mic so the agent can hear the user
await room.localParticipant.setMicrophoneEnabled(true);

End the session​

A session ends when the client disconnects from the LiveKit room. You can also end it explicitly from your backend, without waiting for the client to drop:

POST https://api.lookalike.com/v1/sessions/{session_id}/end

Pass the room_name from the sessions/start response as the session_id. No request body is required.

curl -X POST https://api.lookalike.com/v1/sessions/room-user-001-6014c7ef/end \
-H "Authorization: Bearer $LOOKALIKE_API_KEY"

200 OK:

{
"session_id": "room-user-001-6014c7ef",
"status": "ended",
"identity_id": null,
"pipeline_id": null,
"mode": "meeting_agent",
"metadata": null
}

The call closes the room and disconnects every participant, including the agent. It is idempotent: ending a session that is already gone still returns 200 OK, so it is safe to call after the client has disconnected on its own.

Errors​

StatusMeaning
401 UnauthorizedMissing or invalid API key.
404 Not FoundThe session does not exist, or it belongs to another account.
502 Bad GatewayWe could not confirm the room was closed - retry shortly.

End-to-end example​

import os

import httpx
from livekit import rtc

BASE_URL = "https://api.lookalike.com"
API_KEY = os.environ["LOOKALIKE_API_KEY"]


async def start_session() -> rtc.Room:
"""Start a session with just the persona id and join it with the returned token."""
async with httpx.AsyncClient() as client:
resp = await client.post(
f"{BASE_URL}/v1/sessions/start",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"identity_id": "test-identity-03d39af9"},
)
resp.raise_for_status()
data = resp.json()

room = rtc.Room()
await room.connect(data["livekit_url"], data["token"])
return room

Notes​

  • Avatar audio. When an avatar is enabled it publishes both audio and video. Don't also play the agent's raw voice track, or you'll hear it twice.
  • One token per session. The token is issued per call — start a fresh room for each new session.
  • Ending a session. Disconnect from the LiveKit room, or call POST /v1/sessions/{session_id}/end to end it from your backend.
  • Avatar usage is billed to your account. If you run out of credits, the session ends with an insufficient_credits notice.