Authentication
The API uses two different kinds of credentials, scoped very differently on purpose.
| Secret key | Participant token | |
|---|---|---|
| Format | sk_... | participant_token returned by POST /v1/sessions |
| Lives in | Your server only | Your client (browser / mobile / desktop) |
| Scope | Full account access | One LiveKit room, until expiry |
| Used for | Every REST call (Authorization: Bearer sk_...) | Joining the session’s LiveKit room |
| Can create sessions? | Yes | No |
| Can spend money? | Yes | No |
Secret keys
Section titled “Secret keys”Your secret key authenticates every REST call:
curl https://api.2wai.ai/v1/sessions \ -H "Authorization: Bearer sk_live_..."Keys come in two prefixes:
sk_test_...— test mode. Canned responses on some endpoints; useful for integration tests without burning real pipeline minutes.sk_live_...— real pipeline runs, metered against your account.
Keys are issued when your account is provisioned. See 2wai.ai/developers for the current enrollment + key-issuance flow. Rotating or revoking a key today is a contact-your-account-rep operation; self-serve rotation lives on the developer portal roadmap.
Participant tokens (the mint-proxy pattern)
Section titled “Participant tokens (the mint-proxy pattern)”A participant_token is minted per-session by POST /v1/sessions and is only useful for joining that one session’s LiveKit room. It can’t call any REST endpoint. That’s what makes it safe to hand to a client:
{ "session_id": "ses_4e1f9a2b8c3d", "transport": "livekit", "livekit_url": "wss://2wai.livekit.cloud", "participant_token": "eyJhbGciOi...", "room_name": "ses_4e1f9a2b8c3d", "agent_identity": "livealman-agent-xyz"}Your client passes livekit_url + participant_token to the LiveKit client SDK to join the room. From there the agent appears as another participant and streams its video + audio tracks.
The pattern is called a “mint proxy.” Your server exchanges your sk_ for a participant_token and hands only the token to the client. Every 2wai SDK (Flutter, Web/TypeScript, iOS native) expects a mint-proxy URL as its primary credential — pass the URL, the SDK calls it on connect + reconnect. See Streaming into your app for the shape.
Participant tokens expire (default: a few minutes beyond the session lifetime). The LiveKit SDKs handle reconnect; your mint proxy is called again on reconnect to issue a fresh token.
Putting it together
Section titled “Putting it together”- Client asks your backend (your own API, not a 2wai endpoint) for a session.
- Your backend calls
POST /v1/sessionswithAuthorization: Bearer sk_.... - Your backend returns
livekit_url+participant_token+room_nameto the client. - Client joins the LiveKit room directly. No further REST calls needed from the client.
- Your backend drives the conversation (
/speak,/interrupt) using the secret key, in response to whatever your app logic decides.
Next: Concepts for the vocabulary this builds on, or jump to Sessions for the full lifecycle.