You run a self-hosted LiveKit stack — an SFU you operate, agents built on the LiveKit runtime, ICE/DTLS/SRTP to negotiate, and a media server to keep alive. This page moves that workload onto TeleQuick without rewriting your agent logic. You keep your models, your prompts, and your conversation loop; you drop the SFU and the transport headaches. There are two ways in, and they solve different problems:

Transport in front

Keep your LiveKit agent exactly as it is. Terminate calls on our QUIC transport and bridge the media into your existing LiveKit room. Best when your agent is server-side and you don’t want to touch it.

Drop-in client shim

Swap one import in your browser app. Your Room / RoomEvent / track code keeps compiling but runs over our transport instead of your SFU. Best for the browser leg.
There is no packaged “LiveKit-Agents adapter.” You do not install a plugin into the LiveKit runtime. The two supported paths are (1) putting our transport in front of your unchanged agent via a bridge sidecar, and (2) the browser-side livekit-compat shim. If you would rather hand us the conversation loop entirely and bring only your models, see Keep Your Existing Runtime.

Path 1 — put the transport in front of your agent

This is the lowest-risk migration: your LiveKit agent, room logic, and model plumbing stay byte-for-byte the same. What changes is the media plane in front of them. Callers (PSTN via SIP trunks, or browsers) land on TeleQuick’s single :443 QUIC/WebTransport plane; a lightweight bridge sidecar you run next to your LiveKit deployment carries the audio between our transport and your LiveKit room. The runtime routes a call to that bridge with a first-class vendor-bridge step instead of driving the conversation itself.
caller ──SIP/QUIC──▶  TeleQuick transport  ──vendor bridge──▶  LiveKit room ──▶ your agent
   (PSTN or browser)   (single :443 plane)        (sidecar)          (unchanged)
The vendor-bridge routing is a first-class part of the runtime (its targets are livekit, vapi, and twilio). The bridge sidecar itself is a separate component you deploy alongside your LiveKit stack — it is not bundled into the engine, and its exact packaging depends on your environment. This path is “our transport + your agent,” not a turnkey plugin.
1

Point your inbound numbers at our transport

Move the trunks that feed your LiveKit agent onto TeleQuick. Your carrier trunk terminates on our SIP gateway; numbers are provisioned per tenant under <workspace-id>.sip.telequick.dev. Nothing about your agent changes — only where the call first lands.See SIP Trunking and Number Provisioning.
2

Run the LiveKit bridge sidecar

Deploy the bridge sidecar next to your LiveKit server. It connects to our transport on one side and to your LiveKit room on the other, using your existing LiveKit URL and access-token issuance. Audio is carried across as Opus; your agent sees a normal LiveKit participant.
3

Route calls to the bridge

In the agent configuration for the number, select the vendor bridge target instead of the built-in runtime. Conceptually the agent config carries a vendor-bridge block naming LiveKit as the destination:
{
  "entry_node": "vendor_bridge",
  "vendor_bridge": {
    "vendor": "livekit",
    "room": "support",
    "url": "wss://your-livekit-host.example.com"
  }
}
When a call matches, the runtime hands its media to the bridge rather than running a conversation DAG. Your LiveKit agent joins the room and answers as it always has.
4

Cut over and validate

Move numbers over in waves. On each wave, confirm the call reaches your LiveKit agent, audio is two-way, and your existing telemetry still fires. Because the agent is unchanged, the only new surface is the transport and the bridge — validate those, not your model.
This path is a stepping stone, not a dead end. Once traffic is stable on our transport, you can migrate the runtime itself at your own pace — swapping the vendor bridge for our managed runtime with your own models (BYO ASR/LLM/TTS or BYO Speech-to-Speech) — and retiring the LiveKit stack when you’re ready.

Path 2 — the drop-in client shim (Preview)

Preview / early access. The livekit-compat shim covers the core browser voice path (publish the mic, subscribe to remote audio, exchange data messages) but is not yet a drop-in for every livekit-client API. Video, screenshare, and per-participant E2EE key rotation are deferred; a session-setup race can occasionally deliver zero frames on the first connect (retry). Pin a version and test your flows. For a stable transport-only path, use the raw MoQT primitives in Keep Your Existing Runtime.
If your LiveKit usage is a browser app talking to a room, the shim exposes a livekit-client-compatible surface (Room, RoomEvent, createLocalAudioTrack, participants, tracks) mapped onto our MoQT/QUIC transport. For the common voice path, migration is a one-line import swap — no SFU, no ICE, no media server.
1

Install the shim

npm install @telequick/sdk/livekit-compat
2

Swap the import

Point your existing livekit-client imports at the shim. Your component code is otherwise unchanged.
- import { Room, RoomEvent, createLocalAudioTrack } from "livekit-client";
+ import { Room, RoomEvent, createLocalAudioTrack } from "@telequick/sdk/livekit-compat";
3

Connect to the relay

Your call sites stay the same — the shim reads room and identity from your access token and opens a MoQT session on :443 instead of joining an SFU.
const room = new Room();
await room.connect(url, token);              // your relay.telequick.dev endpoint
await room.localParticipant.setMicrophoneEnabled(true);
room.on(RoomEvent.TrackSubscribed, (track) => track.attach());

How the shim maps LiveKit concepts

Under the hood the shim keeps LiveKit semantics but replaces the media plane entirely — no SFU, no ICE, and WebRTC’s transport is never used. The mic still runs through the browser’s Opus encoder, but only the encoded frames are tapped and shipped over MoQT; see One-Line WebRTC Diversion.
LiveKit conceptRuns as
Room.connect(url, token)A MoQT session over WebTransport on :443
Participant identityA room-scoped MoQT namespace (relay enforces isolation via the token)
Microphone trackEncoded Opus frames published as MoQT objects
Remote audio trackA MoQT subscription decoded with WebCodecs into a Web Audio graph
publishData / DataReceivedA reliable MoQT data track
room.connect() refuses to proceed unless the browser supports encoded media transforms (RTCRtpScriptTransform) — it fails loudly rather than silently falling back to plaintext WebRTC. Today that means Chromium-family browsers, and the browser client is WebTransport-only (no WebSocket fallback leg yet). See Browser Compatibility.

What you gain, and what stays the same

The SFU you operate, ICE/DTLS/SRTP negotiation, TURN relays for blocked networks, and the media server’s scaling and on-call burden. Media rides one QUIC/WebTransport plane on :443.
Your agent logic, prompts, models, and — on Path 1 — your LiveKit room code unchanged. On Path 2, your browser component keeps its Room/RoomEvent shape. We move frames; we don’t impose a runtime.
Both paths read the room and identity out of your existing access token, so your auth/token-minting service does not have to change to get audio flowing.

Keep Your Existing Runtime

The transport-only on-ramps in depth — the shim and the raw MoQT primitives.

LiveKit Agent Integration

Running a LiveKit agent behind our transport, at the integration level.

Migration Overview

Choosing a path across all the products you can move off.

Migration Checklist

The wave-by-wave cutover checklist for any voice migration.