Real-time voice API
Open a live voice session with a project’s agent using an API key: a device, app or SDK connects directly (WebRTC) and talks in real time — to the same agent as on the phone, with its knowledge base and built-in tools.
How it works
- Your backend requests a session:
POST /v1/public/realtime/session(needs awrite-scoped key). - The response is LiveKit room access:
url,token,room. - The device/client joins the room with any LiveKit SDK (JS, Swift, Kotlin, Flutter, Unity, Python…) and enables the microphone.
- The agent joins the room automatically and starts the conversation.
Requesting a session
curl -X POST https://api.maia-ai.com/v1/public/realtime/session \
-H "X-API-Key: maia_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "project_id": "your-project-uuid" }'Response:
{
"url": "wss://lk.maia-ai.com",
"token": "eyJhbGciOi...",
"room": "rt-1a2b3c4d-...",
"expires_in": 3600,
"minute_price": "6.65"
}Connecting a client
Pass url + token to a LiveKit SDK. JS example (livekit-client):
import { Room } from "livekit-client";
const room = new Room();
await room.connect(url, token); // url and token from the response above
await room.localParticipant.setMicrophoneEnabled(true);
// the agent joins the room on its own and starts talkingThe same flow on other platforms — only the LiveKit SDK changes.
Python
from livekit import rtc
room = rtc.Room()
await room.connect(url, token) # url and token from the response above
# publish audio from the device microphone
source = rtc.AudioSource(48000, 1)
track = rtc.LocalAudioTrack.create_audio_track("mic", source)
await room.local_participant.publish_track(track)
# the agent joins the room on its own and starts talkingSwift (iOS)
import LiveKit
let room = Room()
try await room.connect(url: url, token: token) // url and token from the response above
try await room.localParticipant.setMicrophone(enabled: true)
// the agent joins the room on its own and starts talkingKotlin (Android)
val room = LiveKit.create(appContext)
room.connect(url, token) // url and token from the response above
room.localParticipant.setMicrophoneEnabled(true)
// the agent joins the room on its own and starts talkingBilling
The session is billed per minute from the moment of connection at the project’s per-minute
rate (minute_price in the response), like a browser voice session. Active subscription and
sufficient balance are checked before the token is issued — otherwise 402.
The token is valid for 1 hour (expires_in). The session ends when the client disconnects, when
the agent hangs up, or on reaching the duration limit.
Error codes
Responses for POST /v1/public/realtime/session:
| Code | When | What to do |
|---|---|---|
401 | Invalid, revoked or missing API key | Check the X-API-Key or Authorization: Bearer maia_… header |
403 | Key lacks the write scope, or the subscription is suspended | Issue a key with write; check subscription status |
402 | Not enough balance for a session minute | Top up the balance |
404 | Project not found or not owned by the key holder | Check project_id |
429 | Rate limit exceeded (120/min per key) | Slow down requests |
See also: Authentication · REST API · API Reference