ToothFairyAI β Live Sessions API Integration Guide
This guide shows how to integrate ToothFairyAI Live Sessions β mixed text-and-voice chat β into your application. A live session is a single conversation that can switch freely between text turns and realtime voice segments while sharing one chat history, one agent and one mode lock.
How it works (at a glance)β
Your app ββRESTβββΆ /live API βββΆ Agent (text mode, streaming response)
β β²
βββWebRTCβββΆ LiveKit room ββββββββββ (voice mode, realtime audio)
- One session per chat: create (or adopt) a session with
POST /live, then send text turns or start voice segments on it - Mode lock: only one mode (text or voice) is active at a time β starting voice while a text response is streaming returns
409, and vice versa - Attachments at any time: files, images, audios and videos can be attached mid-conversation regardless of the active mode
- Unified transcript:
GET /live/{id}/transcriptreturns every message (text turns, voice transcripts, attachments) in one ordered list
Live sessions are available to all paid users.
Live sessions are currently enabled in the Australia (AU) region. EU and US regions are prepared and will be enabled soon.
Prerequisitesβ
- A ToothFairyAI workspace on a paid plan
- API key generated from Admin β API Integration
- An agent configured in your workspace (voice segments require a voice-enabled agent)
- For voice: the LiveKit client SDK (
livekit-clientfor web)
Base URLβ
| Region | Base URL |
|---|---|
| AU | https://live.toothfairyai.com |
All endpoints accept the workspace API key via the x-api-key header.
Step 1: Create a live sessionβ
Create a session bound to a workspace and agent. If chat_id is omitted a new chat is created; if a chat already has an active session it is adopted ("adopted": true).
curl -X POST https://live.toothfairyai.com/live \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "your-workspace-id",
"agent_id": "your-agent-id",
"name": "Support conversation"
}'
Response
{
"session_id": "07829ac6-56d8-450b-958f-e2f77320a789",
"chat_id": "39fe2008-d086-4bd4-b4c3-6f778c71e1d2"
}
Store both IDs β session_id drives every subsequent call.
Step 2: Send a text turnβ
curl -X POST https://live.toothfairyai.com/live/SESSION_ID/text \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Summarize the report I attached."}'
The response streams back the agent's reply as server-sent events (SSE). The session enters text mode while the response is being generated β starting a voice segment during that window returns 409 SESSION_MODE_LOCKED.
Step 3: Start a realtime voice segmentβ
Voice runs over WebRTC via LiveKit. The flow:
- Call
POST /live/{session_id}/voice/startβ the backend acquires the voice lock and returns a LiveKit access token - Connect to the LiveKit room with that token using the LiveKit client SDK
- Publish your microphone; the agent joins, listens and speaks in realtime
- Call
POST /live/{session_id}/voice/stopwhen done β this releases the lock and lets text turns resume
curl -X POST https://live.toothfairyai.com/live/SESSION_ID/voice/start \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user_id": "user-123"}'
Response
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"url": "wss://livekit.toothfairyai.com",
"room_name": "workspace::chat_ab12cd34"
}
Connecting with the LiveKit SDK (web)β
import { Room } from "livekit-client";
const res = await fetch(`${LIVE_URL}/live/${sessionId}/voice/start`, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId }),
});
const { token, url } = await res.json();
const room = new Room();
await room.connect(url, token);
await room.localParticipant.setMicrophoneEnabled(true);
// The voice agent joins automatically β its audio plays through the room.
// When finished:
await room.disconnect();
await fetch(`${LIVE_URL}/live/${sessionId}/voice/stop`, {
method: "POST",
headers: { "x-api-key": API_KEY },
});
Always call /voice/stop when the user leaves. If a client crashes without stopping, an abandoned voice lock is automatically reclaimed after 30 minutes β but explicit stop is instant.
Step 4: Attach files at any timeβ
Attachments add context without being a turn β they never trigger a reply and work in both text and voice modes. Upload the file to S3 through your normal upload flow first, then register it on the session:
curl -X POST https://live.toothfairyai.com/live/SESSION_ID/attachments \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"files": ["imported_doc_files/ws-1/1730000000000report.pdf"],
"images": ["imported-image/ws-1/1730000000001photo.png"]
}'
All four media kinds are supported: files (documents), images, audios and videos.
During a voice segment, the agent learns about the attachment in realtime and can read it with its read_attachment tool β the user can simply say "what do you make of the document I just sent?". Images are analyzed visually, audio files are transcribed, videos are analyzed, and documents are read as text.
During text mode, attachments become context for the next text turn.
Step 5: Read the unified transcriptβ
curl https://live.toothfairyai.com/live/SESSION_ID/transcript \
-H "x-api-key: YOUR_API_KEY"
Returns every message in order β text turns, voice transcripts (both sides) and attachment markers β so your UI can render one continuous conversation regardless of which mode produced each message.
Step 6: End the sessionβ
curl -X POST https://live.toothfairyai.com/live/SESSION_ID/end \
-H "x-api-key: YOUR_API_KEY"
The session status moves to ended; the chat and its history remain available through the standard chat APIs.
Error handlingβ
| Status | Code | Meaning |
|---|---|---|
| 400 | β | Malformed request (e.g. empty attachment body) |
| 401 | 455 | API key not valid for this workspace |
| 404 | β | Session not found |
| 409 | SESSION_MODE_LOCKED | Another mode is active β stop it first (voice locks auto-release after 30 min if abandoned) |
| 410 | SESSION_ENDED | Session already ended |
| 502 | ATTACHMENT_STORE_FAILED | Attachment message could not be stored β retry |
Complete API referenceβ
The full OpenAPI specification for every endpoint is available at Live Sessions API reference β the TF Live Sessions spec.