Real-time voice

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

  1. Your backend requests a session: POST /v1/public/realtime/session (needs a write-scoped key).
  2. The response is LiveKit room access: url, token, room.
  3. The device/client joins the room with any LiveKit SDK (JS, Swift, Kotlin, Flutter, Unity, Python…) and enables the microphone.
  4. 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 talking

The same flow on other platforms — only the LiveKit SDK changes.

Python

Python SDK:

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 talking

Swift (iOS)

client-sdk-swift:

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 talking

Kotlin (Android)

client-sdk-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 talking

Billing

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:

CodeWhenWhat to do
401Invalid, revoked or missing API keyCheck the X-API-Key or Authorization: Bearer maia_… header
403Key lacks the write scope, or the subscription is suspendedIssue a key with write; check subscription status
402Not enough balance for a session minuteTop up the balance
404Project not found or not owned by the key holderCheck project_id
429Rate limit exceeded (120/min per key)Slow down requests

See also: Authentication · REST API · API Reference