Skip to content
← Developers

Bring your AI voice agent

Put a LiveKit Agents voice agent, or an OpenAI Realtime agent, into a live meeting in a few minutes. Full reference: API documentation.

Steps

  1. Make an API key: Settings → Developer → Create API Key. Copy it once; it is not shown again.
  2. Start or join a meeting yourself. Your agent can only come in while you are there.
  3. Copy the room id: the last part of the meeting link. Put it in the file where it says YOUR_ROOM_ID.
  4. Set your two keys in your environment (below), never in the file.
  5. Run the file. It asks MeetingBurner for a pass, waits if you have not joined yet, then connects to the meeting's audio and starts talking when addressed.
  6. Stop it with Ctrl+C, or end the meeting. It leaves and its time is settled.

Your keys

export MEETINGBURNER_API_KEY=your_meetingburner_key   # Settings → Developer
export OPENAI_API_KEY=your_openai_key                   # from your OpenAI account

(a) A LiveKit Agents voice agent

Speech-to-text, a text model and text-to-speech, wired by the LiveKit Agents framework. Swap any of the three for another LiveKit plugin you prefer. Install with pip install "livekit-agents[openai,silero]~=1.2" httpx.

"""A LiveKit Agents voice agent in a MeetingBurner meeting.

pip install "livekit-agents[openai,silero]~=1.2" httpx
Set MEETINGBURNER_API_KEY and OPENAI_API_KEY in your environment first.
Join the meeting yourself, then run: python agent.py
"""
import asyncio
import os

import httpx
from livekit import rtc
from livekit.agents import Agent, AgentSession
from livekit.plugins import openai, silero

INSTRUCTIONS = "You are a meeting assistant. Speak only when addressed by name, and keep it short."

MEETINGBURNER_API = "https://meetingburner.com/api/v1"
ROOM_ID = "YOUR_ROOM_ID"  # the last part of the meeting link


async def join_meeting(http: httpx.AsyncClient) -> dict:
    """Ask MeetingBurner for a pass. Waits until you are in the meeting yourself."""
    while True:
        response = await http.post(
            f"{MEETINGBURNER_API}/bots/join",
            json={
                "roomId": ROOM_ID,
                "botName": "My Assistant",
                "capabilities": ["listen", "speak"],
                "purpose": "Answers questions when someone asks it by name",
                "waitForOwner": True,
            },
        )
        if response.status_code == 202:  # you have not joined yet
            await asyncio.sleep(response.json()["retryAfterSeconds"])
            continue
        response.raise_for_status()
        return response.json()


async def run_in_meeting(build_session) -> None:
    headers = {"X-API-Key": os.environ["MEETINGBURNER_API_KEY"]}
    async with httpx.AsyncClient(headers=headers, timeout=30) as http:
        join = await join_meeting(http)
        room = rtc.Room()
        ended = asyncio.Event()
        room.on("disconnected", lambda *_: ended.set())
        try:  # from here on, always tell MeetingBurner the agent left
            await room.connect(join["livekitUrl"], join["livekitToken"])
            session = build_session()
            await session.start(agent=Agent(instructions=INSTRUCTIONS), room=room)
            await ended.wait()  # until the meeting ends or you remove the agent
        finally:
            await room.disconnect()
            await http.post(
                f"{MEETINGBURNER_API}/bots/leave",
                json={"connectionId": join["connectionId"]},
            )


def build_pipeline_session() -> AgentSession:
    return AgentSession(
        vad=silero.VAD.load(),
        stt=openai.STT(),
        llm=openai.LLM(),
        tts=openai.TTS(),
    )


if __name__ == "__main__":
    asyncio.run(run_in_meeting(build_pipeline_session))

(b) An OpenAI Realtime agent

One speech-to-speech model hears the meeting and answers in voice. The join and leave are the same as (a); only the session differs. Install with pip install "livekit-agents[openai]~=1.2" httpx.

"""An OpenAI Realtime voice agent in a MeetingBurner meeting.

pip install "livekit-agents[openai]~=1.2" httpx
Set MEETINGBURNER_API_KEY and OPENAI_API_KEY in your environment first.
Join the meeting yourself, then run: python agent.py
"""
import asyncio
import os

import httpx
from livekit import rtc
from livekit.agents import Agent, AgentSession
from livekit.plugins import openai

INSTRUCTIONS = "You are a meeting assistant. Speak only when addressed by name, and keep it short."

MEETINGBURNER_API = "https://meetingburner.com/api/v1"
ROOM_ID = "YOUR_ROOM_ID"  # the last part of the meeting link


async def join_meeting(http: httpx.AsyncClient) -> dict:
    """Ask MeetingBurner for a pass. Waits until you are in the meeting yourself."""
    while True:
        response = await http.post(
            f"{MEETINGBURNER_API}/bots/join",
            json={
                "roomId": ROOM_ID,
                "botName": "My Assistant",
                "capabilities": ["listen", "speak"],
                "purpose": "Answers questions when someone asks it by name",
                "waitForOwner": True,
            },
        )
        if response.status_code == 202:  # you have not joined yet
            await asyncio.sleep(response.json()["retryAfterSeconds"])
            continue
        response.raise_for_status()
        return response.json()


async def run_in_meeting(build_session) -> None:
    headers = {"X-API-Key": os.environ["MEETINGBURNER_API_KEY"]}
    async with httpx.AsyncClient(headers=headers, timeout=30) as http:
        join = await join_meeting(http)
        room = rtc.Room()
        ended = asyncio.Event()
        room.on("disconnected", lambda *_: ended.set())
        try:  # from here on, always tell MeetingBurner the agent left
            await room.connect(join["livekitUrl"], join["livekitToken"])
            session = build_session()
            await session.start(agent=Agent(instructions=INSTRUCTIONS), room=room)
            await ended.wait()  # until the meeting ends or you remove the agent
        finally:
            await room.disconnect()
            await http.post(
                f"{MEETINGBURNER_API}/bots/leave",
                json={"connectionId": join["connectionId"]},
            )


def build_realtime_session() -> AgentSession:
    return AgentSession(llm=openai.realtime.RealtimeModel(voice="alloy"))


if __name__ == "__main__":
    asyncio.run(run_in_meeting(build_realtime_session))

(c) No API key: join with an invite code

If you host the meeting, open Settings → Invite your agent and copy the code. It works for this meeting only, once, within ten minutes, and the agent's time comes from your tokens. Set it as MEETINGBURNER_INVITE_CODE and run the file below: the same agent as (b), joining at /bots/join-with-code. To leave, it uses the connectionToken that join returns. If it drops, ask for a fresh code; a used code never works again.

"""An OpenAI Realtime agent that joins with a one-time MeetingBurner invite code.

pip install "livekit-agents[openai]~=1.2" httpx
Set MEETINGBURNER_INVITE_CODE (from "Invite your agent") and OPENAI_API_KEY first.
Join the meeting yourself, then run: python agent.py
"""
import asyncio
import os

import httpx
from livekit import rtc
from livekit.agents import Agent, AgentSession
from livekit.plugins import openai

INSTRUCTIONS = "You are a meeting assistant. Speak only when addressed by name, and keep it short."

MEETINGBURNER_API = "https://meetingburner.com/api/v1"
INVITE_CODE = os.environ["MEETINGBURNER_INVITE_CODE"]  # one meeting, one use, ten minutes


async def join_meeting(http: httpx.AsyncClient) -> dict:
    """Ask MeetingBurner for a pass. Waits until you are in the meeting yourself."""
    while True:
        response = await http.post(
            f"{MEETINGBURNER_API}/bots/join-with-code",
            json={
                "code": INVITE_CODE,
                "botName": "My Assistant",
                "capabilities": ["listen", "speak"],
                "purpose": "Answers questions when someone asks it by name",
                "waitForOwner": True,
            },
        )
        if response.status_code == 202:  # you have not joined yet
            await asyncio.sleep(response.json()["retryAfterSeconds"])
            continue
        response.raise_for_status()
        return response.json()


async def run_in_meeting(build_session) -> None:
    headers = {}  # no API key: the code is the whole credential
    async with httpx.AsyncClient(headers=headers, timeout=30) as http:
        join = await join_meeting(http)
        room = rtc.Room()
        ended = asyncio.Event()
        room.on("disconnected", lambda *_: ended.set())
        try:  # from here on, always tell MeetingBurner the agent left
            await room.connect(join["livekitUrl"], join["livekitToken"])
            session = build_session()
            await session.start(agent=Agent(instructions=INSTRUCTIONS), room=room)
            await ended.wait()  # until the meeting ends or you remove the agent
        finally:
            await room.disconnect()
            await http.post(
                "https://meetingburner.com/api/agents/disconnect",
                headers={"Authorization": f"Bearer {join['connectionToken']}"},
            )


def build_realtime_session() -> AgentSession:
    return AgentSession(llm=openai.realtime.RealtimeModel(voice="alloy"))


if __name__ == "__main__":
    asyncio.run(run_in_meeting(build_realtime_session))

Why it is not a dispatched LiveKit worker

LiveKit can start agents for you when a room opens, but only with the media server's own secret, which stays with MeetingBurner. So your agent runs as its own program and connects with the pass /bots/join gives it: livekitUrl and livekitToken. The pass works for this one meeting only. You pay your model provider directly; MeetingBurner never resells model time.

The rules in the room

  • Everyone is told. Your agent's name, its purpose and your name are shown to every person in the meeting. A join without a purpose is refused.
  • You must be there. An agent joins only while you are in the meeting, and it is removed when you leave.
  • The host decides. A host can turn off guests' agents for a meeting. Agents are refused in private and off-the-record meetings, and nothing is created for them.
  • Bring several. A meeting holds up to 10 agents from everyone together, with no per-person cap (your plan may set a smaller allowance). Any of your agents may speak, only one of them may be on camera at a time, and each agent in the room needs a distinct name.

Cost

A speaking agent is charged to your account at the voice rate, rounded up to whole tokens: a one-minute call costs 10 tokens, and 10 minutes cost 100 tokens. Your balance must cover the first minute before the agent is let in. Every rate is on Usage and Tokens.