Skip to main content

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}/transcript returns every message (text turns, voice transcripts, attachments) in one ordered list
Plan Requirements

Live sessions are available to all paid users.

Region availability

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-client for web)

Base URL​

RegionBase URL
AUhttps://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:

  1. Call POST /live/{session_id}/voice/start — the backend acquires the voice lock and returns a LiveKit access token
  2. Connect to the LiveKit room with that token using the LiveKit client SDK
  3. Publish your microphone; the agent joins, listens and speaks in realtime
  4. Call POST /live/{session_id}/voice/stop when 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 },
});
Releasing the voice lock

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​

StatusCodeMeaning
400—Malformed request (e.g. empty attachment body)
401455API key not valid for this workspace
404—Session not found
409SESSION_MODE_LOCKEDAnother mode is active — stop it first (voice locks auto-release after 30 min if abandoned)
410SESSION_ENDEDSession already ended
502ATTACHMENT_STORE_FAILEDAttachment 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.