Skip to content

Create a session

POST
/v1/sessions
curl --request POST \
--url https://example.com/v1/sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "avatar_id": "av_demo", "idle_timeout_seconds": 30, "max_duration_seconds": 600, "metadata": { "customer_session_id": "abc123" }, "quality": "standard", "transport": { "room_name": "demo-room", "type": "livekit", "url": "wss://my-app.livekit.cloud", "worker_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } }'

Allocate a worker and begin a realtime avatar session.

Returns immediately with status: queued; poll GET /v1/sessions/{id} (or wait for the session.first_frame webhook) to see the worker pick the job up. Sessions count against your plan’s concurrency cap; a 503 response with code=at_capacity and a Retry-After header means there are no free workers right now.

Media type application/json
SessionCreateRequest

Request body for POST /v1/sessions.

object
avatar_id
required

av_… prefixed ULID. Must reference an avatar the caller’s API key can access.

string
idle_timeout_seconds

End the session automatically after this many seconds without received audio. Only applies to transports that observe inbound audio; ignored otherwise.

integer
default: 30 >= 1 <= 600
max_duration_seconds

Hard ceiling on session duration; worker terminates on hit.

integer
default: 600 >= 1 <= 3600
metadata

Customer-owned free-form JSON, ≤ 8 KB. Echoed on webhooks. Keys prefixed with _avatar. are reserved.

object
key
additional properties
Any of:
string
quality
QualityTier

Quality tier; drives the billing multiplier.

string
default: standard
Allowed values: mock lite standard pro
transport
required
One of: discriminator: type
LiveKitTransportConfig

BYO LiveKit transport.

The customer owns the room and mints worker_token; we never touch their LiveKit API key or secret.

object
audio_source
LiveKitAudioSource

How the worker receives audio. See LiveKitAudioSource.

string
default: data_stream
Allowed values: data_stream track
room_name
required

Name of the LiveKit room the worker should join.

string
subscribe_to_identity
Any of:
string
synthetic_audio_if_no_input

If True and no participant joins within 10 s, the worker falls back to a synthetic sine generator. Demo aid only; default off.

boolean
type
string
default: livekit
Allowed value: livekit
url
required

Customer’s LiveKit URL, e.g. wss://my-app.livekit.cloud.

string
worker_identity

Identity the worker presents inside the room.

string
default: protoface-worker
worker_token
required

Short-lived JWT the customer mints authorizing our worker to join the room. Write-only. Never echoed back on read; GET /v1/sessions/{id}.transport.worker_token returns the string "[redacted]".

string

Successful Response

Media type application/json
Session

Public session resource — what GET /v1/sessions/{id} returns.

object
avatar_id
required
string
created_at
required
string format: date-time
ended_at
Any of:
string format: date-time
failed_at
Any of:
string format: date-time
failure
Any of:
SessionFailure

Populated when Session.status == failed.

object
code
required

Stable lower_snake_case subcode.

string
message
required

Human-readable summary; not stable.

string
first_frame_at
Any of:
string format: date-time
id
required

sess_… prefixed ULID.

string
idle_timeout_seconds
required
integer
max_duration_seconds
required
integer
metadata
required
object
key
additional properties
Any of:
string
object
string
default: session
Allowed value: session
quality
required
QualityTier

Output quality tier. Drives the credit billing multiplier.

standard is the default for new sessions. mock is reserved for internal tests and the bring-up runtime (no real model loaded); it bills as standard when it appears on a real session.

string
Allowed values: mock lite standard pro
started_at
Any of:
string format: date-time
status
required
SessionStatus

Public session lifecycle.

Terminal states are ended, failed, canceled. ending is the graceful-drain state while a worker finishes publishing in-flight frames.

string
Allowed values: created queued starting running ending ended failed canceled
transport
required
One of: discriminator: type
LiveKitTransportConfig

BYO LiveKit transport.

The customer owns the room and mints worker_token; we never touch their LiveKit API key or secret.

object
audio_source
LiveKitAudioSource

How the worker receives audio. See LiveKitAudioSource.

string
default: data_stream
Allowed values: data_stream track
room_name
required

Name of the LiveKit room the worker should join.

string
subscribe_to_identity
Any of:
string
synthetic_audio_if_no_input

If True and no participant joins within 10 s, the worker falls back to a synthetic sine generator. Demo aid only; default off.

boolean
type
string
default: livekit
Allowed value: livekit
url
required

Customer’s LiveKit URL, e.g. wss://my-app.livekit.cloud.

string
worker_identity

Identity the worker presents inside the room.

string
default: protoface-worker
worker_token
required

Short-lived JWT the customer mints authorizing our worker to join the room. Write-only. Never echoed back on read; GET /v1/sessions/{id}.transport.worker_token returns the string "[redacted]".

string
usage
SessionUsage

Live usage counters embedded in the Session resource.

Eventually-consistent — lags the latest worker heartbeat by up to one interval. Canonical billing data lives in UsageEvent.

object
billable_seconds
required
integer
frames
required
integer
Example
{
"avatar_id": "av_demo",
"created_at": "2026-05-25T19:00:00.123Z",
"first_frame_at": "2026-05-25T19:00:02.001Z",
"id": "sess_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"idle_timeout_seconds": 30,
"max_duration_seconds": 600,
"metadata": {
"customer_session_id": "abc123"
},
"object": "session",
"quality": "standard",
"started_at": "2026-05-25T19:00:01.456Z",
"status": "running",
"transport": {
"audio_source": "data_stream",
"room_name": "demo-room",
"type": "livekit",
"url": "wss://my-app.livekit.cloud"
},
"usage": {
"billable_seconds": 12,
"frames": 300
}
}

Invalid request body.

Media type application/json
ApiErrorEnvelope

Wire format for every non-2xx public API response.

object
error
required
ApiError

Concrete error returned inside ApiErrorEnvelope.error.

object
code
required

Stable machine-readable subcode (lower_snake_case). SDKs should switch on this, not message.

string
message
required

Human-readable summary. Not stable; do not parse.

string
param
Any of:
string
request_id
required

Echo of the X-Request-Id response header for support.

string
type
required
ErrorType

Top-level error categories. Maps roughly to HTTP status.

code (a free-form lower_snake_case string on ApiError) is the machine-readable subcode SDKs should switch on; type is the broad category.

string
Allowed values: invalid_request authentication permission not_found conflict unprocessable rate_limit quota_exceeded internal service_unavailable
Example
{
"error": {
"code": "transport.unsupported",
"message": "transport.type=pipecat is reserved and not yet available",
"param": "transport.type",
"request_id": "req_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"type": "invalid_request"
}
}

Missing or invalid API key.

Media type application/json
ApiErrorEnvelope

Wire format for every non-2xx public API response.

object
error
required
ApiError

Concrete error returned inside ApiErrorEnvelope.error.

object
code
required

Stable machine-readable subcode (lower_snake_case). SDKs should switch on this, not message.

string
message
required

Human-readable summary. Not stable; do not parse.

string
param
Any of:
string
request_id
required

Echo of the X-Request-Id response header for support.

string
type
required
ErrorType

Top-level error categories. Maps roughly to HTTP status.

code (a free-form lower_snake_case string on ApiError) is the machine-readable subcode SDKs should switch on; type is the broad category.

string
Allowed values: invalid_request authentication permission not_found conflict unprocessable rate_limit quota_exceeded internal service_unavailable
Example
{
"error": {
"code": "transport.unsupported",
"message": "transport.type=pipecat is reserved and not yet available",
"param": "transport.type",
"request_id": "req_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"type": "invalid_request"
}
}

Conflicting state (e.g. avatar not ready).

Media type application/json
ApiErrorEnvelope

Wire format for every non-2xx public API response.

object
error
required
ApiError

Concrete error returned inside ApiErrorEnvelope.error.

object
code
required

Stable machine-readable subcode (lower_snake_case). SDKs should switch on this, not message.

string
message
required

Human-readable summary. Not stable; do not parse.

string
param
Any of:
string
request_id
required

Echo of the X-Request-Id response header for support.

string
type
required
ErrorType

Top-level error categories. Maps roughly to HTTP status.

code (a free-form lower_snake_case string on ApiError) is the machine-readable subcode SDKs should switch on; type is the broad category.

string
Allowed values: invalid_request authentication permission not_found conflict unprocessable rate_limit quota_exceeded internal service_unavailable
Example
{
"error": {
"code": "transport.unsupported",
"message": "transport.type=pipecat is reserved and not yet available",
"param": "transport.type",
"request_id": "req_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"type": "invalid_request"
}
}

Request body failed validation.

Media type application/json
ApiErrorEnvelope

Wire format for every non-2xx public API response.

object
error
required
ApiError

Concrete error returned inside ApiErrorEnvelope.error.

object
code
required

Stable machine-readable subcode (lower_snake_case). SDKs should switch on this, not message.

string
message
required

Human-readable summary. Not stable; do not parse.

string
param
Any of:
string
request_id
required

Echo of the X-Request-Id response header for support.

string
type
required
ErrorType

Top-level error categories. Maps roughly to HTTP status.

code (a free-form lower_snake_case string on ApiError) is the machine-readable subcode SDKs should switch on; type is the broad category.

string
Allowed values: invalid_request authentication permission not_found conflict unprocessable rate_limit quota_exceeded internal service_unavailable
Example
{
"error": {
"code": "transport.unsupported",
"message": "transport.type=pipecat is reserved and not yet available",
"param": "transport.type",
"request_id": "req_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"type": "invalid_request"
}
}

Rate limit exceeded.

Media type application/json
ApiErrorEnvelope

Wire format for every non-2xx public API response.

object
error
required
ApiError

Concrete error returned inside ApiErrorEnvelope.error.

object
code
required

Stable machine-readable subcode (lower_snake_case). SDKs should switch on this, not message.

string
message
required

Human-readable summary. Not stable; do not parse.

string
param
Any of:
string
request_id
required

Echo of the X-Request-Id response header for support.

string
type
required
ErrorType

Top-level error categories. Maps roughly to HTTP status.

code (a free-form lower_snake_case string on ApiError) is the machine-readable subcode SDKs should switch on; type is the broad category.

string
Allowed values: invalid_request authentication permission not_found conflict unprocessable rate_limit quota_exceeded internal service_unavailable
Example
{
"error": {
"code": "transport.unsupported",
"message": "transport.type=pipecat is reserved and not yet available",
"param": "transport.type",
"request_id": "req_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"type": "invalid_request"
}
}

No worker capacity; retry later.

Media type application/json
ApiErrorEnvelope

Wire format for every non-2xx public API response.

object
error
required
ApiError

Concrete error returned inside ApiErrorEnvelope.error.

object
code
required

Stable machine-readable subcode (lower_snake_case). SDKs should switch on this, not message.

string
message
required

Human-readable summary. Not stable; do not parse.

string
param
Any of:
string
request_id
required

Echo of the X-Request-Id response header for support.

string
type
required
ErrorType

Top-level error categories. Maps roughly to HTTP status.

code (a free-form lower_snake_case string on ApiError) is the machine-readable subcode SDKs should switch on; type is the broad category.

string
Allowed values: invalid_request authentication permission not_found conflict unprocessable rate_limit quota_exceeded internal service_unavailable
Example
{
"error": {
"code": "transport.unsupported",
"message": "transport.type=pipecat is reserved and not yet available",
"param": "transport.type",
"request_id": "req_01HXY5K8E7QYG3X8Z6N9R7S0VR",
"type": "invalid_request"
}
}