Start a conversation session
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.
visitorIdis 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.
X-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_....
application/json- body
Request body for POST /v1/sessions, the same for every
credential. Always LiveKit.
avatarId*stringID of the avatar to launch. With an API key, it must be on the key's allow-list.
length <= 36maxDurationSeconds?integerMaximum duration of the session in seconds. If not provided, uses the key's/plan's/balance's maximum. Capped server-side.
1 <= value <= 14400visitorId?stringOpaque 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.
8 <= length <= 256language?stringPer-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.
^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$length <= 35metadata?Optional free-form metadata to attach to the session (stored as JSONB).
properties <= 50location?Optional location metadata to attach to the session (stored as JSONB).
properties <= 20sttMultilingual?booleanRecognise 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?numberSeconds 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.
double0 <= value <= 3600welcome?booleanfalse 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.
The session started; the avatar has already joined the room.
application/json- 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*stringID of the created session
uuidserverUrl*stringBare LiveKit server URL — pass directly to Room.connect(). Never has a room path appended.
uriroomName*stringLiveKit room name, informational only — the token already selects the room.
userToken*stringLiveKit access token for the visitor's browser to join with.
actualDurationSeconds?integerSession 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?integerThe maxDurationSeconds you sent; omitted when you sent none.
durationCapped?booleanTrue when actualDurationSeconds is shorter than
requestedDurationSeconds: the key's, the plan's or the
balance's limit cut the session you asked for.
billingMode*stringHow 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.
"reserve""metered"curl -X POST 'https://api.atmanity.us/v1/sessions' \ -H 'Content-Type: application/json' \ -d '{ "avatarId": "123e4567-e89b-12d3-a456-426614174000"}'{ "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"}Voice design
Design a voice from a description of how it should sound, and get previews of 10 to 60 seconds, the length an avatar's voice sample needs.
Read a session's state, end reason and cost GET
Reads a session started with an API key (POST /v1/sessions or POST /v1/avatar_sessions): the same read as GET /v1/avatar_sessions/{id}.

