Skip to content

End a session

POST
/v1/sessions/{session_id}/end
curl --request POST \
--url https://example.com/v1/sessions/example/end \
--header 'Authorization: Bearer <token>'

Terminate a session immediately. Idempotent: calling on an already-terminal session returns 200 with the existing state. The session transitions to canceled if it had not yet started, or ending (then ended once the worker drains) if it was running.

session_id
required
Session Id

sess_… prefixed ULID.

string

sess_… prefixed ULID.

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
}
}

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"
}
}

No session with that id.

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 or parameters 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"
}
}