I’m searching to know the most efficient/reliable way to send external events to a livekit room/agent.
Use case
My use case is that tool calls in Livekit are initiated as background tasks. I’m using Inngest to handle background. This is how
Here is the link to my livekit agent.py file Livkeit & Inngest · GitHub . It shows how I’m initiating tool calls in Livekit as background jobs done outside of livekit.
I want when my backend server Inngest completes or reaches the desired step (completes task), then it should inform livekit room/agent that tool call is done and then provide the tool result.
How I have navigated this so far
Whenever I need to inform the livekit agent/room, I have been using SendData in Livekit & using session.generate_reply to inject the update into the conversation.
This is my code that does SendData whenever an external event happens
from pydantic import BaseModel
class SendData(BaseModel):
room_name: str
message_type: str
message_text: str
def create_room_admin_token(room: str) -> str:
token = api.AccessToken(os.getenv('LIVEKIT_API_KEY'),
os.getenv('LIVEKIT_API_SECRET')) \
.with_identity("Token-Generator") \
.with_name("Kamal") \
.with_grants(api.VideoGrants(
room_join=True,
room_admin=True,
can_publish=True,
can_subscribe=True,
room=room)).to_jwt()
return token
async def send_data_to_agent(content: SendData):
token = create_room_admin_token(content.room_name)
print(f"TOKEN:{token}")
# Your business event payload
payload = content.model_dump()
print(f"PAYLOAD: {payload}")
encoded_data = base64.b64encode(
json.dumps(payload).encode("utf-8")
).decode("utf-8")
print(f"Encoded Data: {encoded_data}")
# Convert WebSocket URL to HTTP API URL
api_url = os.environ.get('LIVEKIT_URL').replace('wss://', 'https://').replace('ws://', 'http://')
if not api_url.endswith('/'):
api_url += '/'
print(f"API URL: {api_url}")
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
payload={
"room": content.room_name,
"data": encoded_data,
"kind": "reliable",
# "destination_identities": [AGENT_IDENTITY],
"destination_identities": None,
# "topic": "backend-event",
}
# Send data message via REST API
url = f"{api_url}twirp/livekit.RoomService/SendData"
response = requests.post(url, json=payload, headers=headers, timeout=10)
if response.status_code == 200:
print(f"Successfully sent message to room")
return f"Successfully sent message to room"
else:
print(f"Failed to send message. Status: {response.status_code}, Response: {response.text}")
raise Exception(f"LiveKit API error: {response.status_code} - {response.text}")
As you can see, I have set kind to reliable
What I’m trying to do
I’m building an agent using Whatsapp connector. Here is how flow is & the steps taken:
- User calls the whatsapp number
- Agent answers the call & has a normal conversation with the user
- User sends a whatsapp message. Our backend receives a webhook event from Meta
- We now need to inform the livekit agent about this new message. The livekit agent can use this message to execute a tool.
- Livekit agent executes a tool. I’m using inngest to run the tool as a background task
- When tool is successful, inform the livekit agent that the tool is successful and provide it the result.
- Then message the user on Whatsapp a summary of tool result.
Every step is orchestrated by inngest because my use case depends on external platforms (Meta, Livekit, etc) exchanging events/data/information.
How I have navigated this
For steps 4 & 6 where I need to inform the livekit agent, I have been using SendData in Livekit & using session.generate_reply to inject the update into the conversation.
Problems I have faced
For steps 4 & 6 where I need I have noticed that SendData is not a very reliable method of updating the agent of what has been done in the backend. In my testing, I have noticed several times that even if when I do SendData, the agent is not even aware of what it has been sent and continues to say I’m still working on executing the tool, yet the tool has already been executed and results were shared to it.
Watch this quick video I have recorded > https://youtu.be/smxC5W2GQaY
By about 2:17 in the above video, the Livekit agent/room was sent data from my backend. But the agent is not aware of anything and doesn’t know tool result throughout the entire session.
Watch the above video.
I also get these errors in the logs
2026-08-31 05:05:09,544 - ERROR livekit - livekit::rtc_engine::rtc_session:679:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly {"pid": 1948, "job_id": "AJ_ZTfqJHAgEVKd", "room": "whatsapp-room"}
2026-08-31 05:05:09,545 - ERROR livekit - livekit::rtc_engine::rtc_session:679:livekit::rtc_engine::rtc_session - publisher data channel '_lossy' closed unexpectedly {"pid": 1948, "job_id": "AJ_ZTfqJHAgEVKd", "room": "whatsapp-room"}
2026-08-31 05:05:09,547 - ERROR livekit - livekit::rtc_engine::rtc_session:679:livekit::rtc_engine::rtc_session - publisher data channel '_data_track' closed unexpectedly {"pid": 1948, "job_id": "AJ_ZTfqJHAgEVKd", "room": "whatsapp-room"}
Reason I’m picking inngest
- Durable execution
- It’s event driven and provides reliable runs of several separate steps & agent actions
- Idempotency
- Does retries if tool execution fails
- State persistence
For example, this is what happens when I execute/trigger a livekit tool. This is how the backend orchestrates multiple steps.
For my use case, multiple steps need to take place and that’s why execution needs to be outside of livekit. But it’s VERY important I inform the active livekit room/agent about what’s happening on the backend.
Questions
- What is the most efficient way to send external events/webhooks/data to a livekit room/agent?
- When sending external data to a room, how can you inform that this is tool response/result.




