← Developers

Bring your 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.
  • One voice each. You may have one speaking agent in a meeting at a time; extra listening agents are allowed up to your plan's limit.

Cost

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