Atmee.aiDocs
APIAPI referenceSession

Start a conversation session

POST
/v1/sessions

Starts a full conversation: the avatar listens, thinks and answers in a LiveKit room the visitor joins. One request and one response whatever the credential; the credential decides who pays:

  • API key (X-Api-Key) — your backend starts a session for a visitor of yours, billed to your account. Called server to server, never from a browser.
  • Signed-in user (Authorization: Bearer <jwt>) — a visitor of the Atmee website, signed in or anonymous. The avatar's settings decide whether the visitor or the avatar's owner pays.
  • No credential — a visitor on an avatar whose owner sponsors anonymous chat, paid from the avatar's sponsor budget and rate-limited per client IP. visitorId is required.

Responds 201 once the avatar has joined the room, with what livekit-client's Room.connect() needs. Length. maxDurationSeconds is capped server-side (the key's and the plan's limits, and for reserve billing what the balance can pay for); the response reports what you asked for, what you got and whether it was cut. The visitor must join within 60 seconds of the avatar, or the session ends failed with nothing billed.

Ending. POST /v1/sessions/{id}/end with the credential that started it. Read an API session's state, end reason and cost with GET /v1/sessions/{id}. An avatar renders one live conversation at a time per account: a second start answers 409 avatar_busy.

App tools (API key only). appTools.tools declares functions the avatar may call; each call reaches the visitor's LiveKit client as an RPC (method atmee.tool, payload {id, name, arguments}). With x-atmee.mode await its answer is the result the avatar is given. The request body may be up to 128 KiB.

Authorization

headerX-Api-Key<token>

Secret embed API key (sk_atmee_...; keys minted before 2026-09 carry sk_live_...), held by the customer's own backend and never sent to a browser. Format: X-Api-Key: sk_atmee_....

Request Body

application/json
  1. body

Request body for POST /v1/sessions, the same for every credential. Always LiveKit.

avatarId*string

ID of the avatar to launch. With an API key, it must be on the key's allow-list.

Lengthlength <= 36
maxDurationSeconds?integer

Maximum duration of the session in seconds. If not provided, uses the key's/plan's/balance's maximum. Capped server-side.

Range1 <= value <= 14400
visitorId?string

Opaque identifier for this visitor. With an API key it is at least 16 characters and only meaningful when the key has cross-visit memory enabled; it must be an unguessable value derived from your own server-side session (whoever can name it reads that visitor's conversation history). Without a credential it is required, at most 64 characters, and counts the visitor's free daily time. Ignored for a signed-in user.

Length8 <= length <= 256
language?string

Per-session language override (BCP-47), e.g. en, zh-TW, ja. Omit to use the avatar's own language. Any well-formed tag is accepted and forwarded; the runtime routes speech recognition and responses for en, zh-TW and ja today and falls back to language auto-detection for other tags.

Match^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$
Lengthlength <= 35
metadata?

Optional free-form metadata to attach to the session (stored as JSONB).

Propertiesproperties <= 50
location?

Optional location metadata to attach to the session (stored as JSONB).

Propertiesproperties <= 20
sttMultilingual?boolean

Recognise speech in any supported language instead of the session's language only.

appTools?

API key only; with any other credential the start answers 400 invalid_request.

checkInAfterS?number

Seconds of silence before the avatar speaks up in character, from 0 to 3600; a second check-in waits twice as long, then it stays quiet until the visitor speaks. 0 turns the check-in off. Absent or null keeps the default, about 10 seconds. Needs a v2 avatar that launches on the default conversation runtime, as every avatar built through this API does; any other answers 400 check_in_not_supported, with nothing billed. Billing and session length are the same either way.

Formatdouble
Range0 <= value <= 3600
welcome?boolean

false starts the session without the avatar's welcome: no self-introduction and no welcome back, first visit or return. It waits for the visitor to speak and answers as usual; a long silence still gets its check-in, which checkInAfterS sets or turns off. Absent, null or true, the avatar speaks first, as it always has. Needs a v2 avatar that launches on the default conversation runtime, as every avatar built through this API does; any other answers 400 welcome_not_supported, with nothing billed. Billing and session length are the same either way.

Response Body

The session started; the avatar has already joined the room.

application/json
  1. response

Response body for /v1/sessions's 201 response. Deliberately different from SessionStartResponse: serverUrl and roomName are split out because the combined roomUrl used elsewhere cannot be passed directly to livekit-client's Room.connect().

links?

Absent when this deployment does not know the website's address.

sessionId*string

ID of the created session

Formatuuid
serverUrl*string

Bare LiveKit server URL — pass directly to Room.connect(). Never has a room path appended.

Formaturi
roomName*string

LiveKit room name, informational only — the token already selects the room.

userToken*string

LiveKit access token for the visitor's browser to join with.

actualDurationSeconds?integer

Session duration granted by the key/plan/balance limits, in seconds, counted from the moment both the visitor and the avatar are in the room. Omitted when the session is uncapped (billingMode metered on a key without max_session_seconds): do not start a countdown from a missing value. A metered session ends when the account's balance or the key's spend cap runs out, after a short grace, or at the operator ceiling.

requestedDurationSeconds?integer

The maxDurationSeconds you sent; omitted when you sent none.

durationCapped?boolean

True when actualDurationSeconds is shorter than requestedDurationSeconds: the key's, the plan's or the balance's limit cut the session you asked for.

billingMode*string

How the session is billed. reserve locks the whole granted duration when the session starts and releases the unused part at the end. metered charges the elapsed time in one-minute ticks while the session runs; nothing is locked up front.

Value in"reserve""metered"
Example Request
curl -X POST 'https://api.atmanity.us/v1/sessions' \  -H 'Content-Type: application/json' \  -d '{  "avatarId": "123e4567-e89b-12d3-a456-426614174000"}'
Example Response
{  "links": {    "chat": "http://example.com"  },  "sessionId": "550e8400-e29b-41d4-a716-446655440000",  "serverUrl": "wss://atmanity.livekit.cloud",  "roomName": "rk-8f14e45f-ceea-467a-9f21-4c2f5b3a91cd",  "userToken": "string",  "actualDurationSeconds": 0,  "requestedDurationSeconds": 0,  "durationCapped": true,  "billingMode": "reserve"}