:443 plane — no ICE/DTLS/SRTP negotiation and no media
server to operate.
There are three ways to plug a runtime in, from least code to most control:
Vendor bridge
A config node, no code. Point a call at an external orchestration vendor
(LiveKit / Vapi / Twilio); we stay the transport in front of it.
Raw MoQT bridge
Subscribe the caller’s uplink, publish your reply as downlink. You
own capture, model, and playback; we move the frames. The stable path.
LiveKit-compat shim
A
livekit-client-shaped surface over our transport. Swap one import.
Route 1 — bridge to an external vendor
If your “runtime” is really another orchestration product — a LiveKit Agent, a Vapi assistant, a Twilio app — you do not integrate it in code at all. You add aVENDOR_BRIDGE node to the agent’s pipeline config. When the runtime sees
it, it hands the call’s media to that vendor over an external bridge sidecar
instead of running our own ASR→LLM→TTS pipeline; TeleQuick stays the QUIC
transport in front of the vendor’s media backend.
The config is a single node in the agent’s pipeline document:
The external orchestration vendor:
livekit, vapi, or twilio. Selects
which bridge protocol the sidecar speaks.The vendor-side target — a LiveKit room, a Vapi assistant id, or a Twilio app.
A reference into the tenant’s stored vendor credentials (sealed at rest), so
the vendor’s keys never live in the pipeline document.
agent.telequick.dev or through the control-plane
API, then point a trunk or an outbound call at the agent. See the vendor-specific
pages for the exact room/credential shape:
LiveKit Agent
Run a LiveKit agent behind our transport.
Pipecat
Run a Pipecat pipeline behind our transport.
Route 2 — the raw MoQT audio bridge
This is the direct path and the one most custom runtimes want: attach to a live call, receive the caller’s audio frames, and push your reply frames back. Every call is addressed by itscall_sid, and its audio lives on two MoQT tracks
under a room-scoped namespace:
| Track | Direction | You |
|---|---|---|
voice/<sid>/uplink | caller → you | subscribe to hear the caller |
voice/<sid>/downlink | you → caller | publish your runtime’s reply |
AudioBridge wraps both tracks behind one handle: attach()
subscribes the uplink and publishes the downlink for you. What sits between
onUplink and publishDownlink is entirely yours — your VAD, your turn-taking,
your model.
Attach to the call
Open the bridge with the call’s
call_sid. Choose the codec that matches the
leg — opus for browser/app callers, g711_ulaw/g711_alaw or pcm16 for
phone callers.Consume the uplink
Your
onUplink callback fires for every inbound audio frame. Feed it to your
runtime’s input — your ASR, your speech-to-speech session, whatever you run.Publish the downlink
When your runtime produces reply audio, call
publishDownlink(frame) per
encoded frame (for example one 20 ms Opus packet). The caller hears it.- TypeScript
- Python
Same shape in every SDK. Go, Rust, Java, and .NET expose the same
attach / publish_downlink primitives through a shared native core. The
native bindings speak QUIC/MoQT directly and do not ship the browser’s
WebSocket/WebRTC fallback leg — plan for a QUIC-reachable network. See the
transport SDK reference for per-language
method and event names.Namespace rule. Track namespaces are room-scoped tuples with a non-empty
prefix and suffix; empty tuples are rejected by the media-over-QUIC engine.
The
voice/<sid>/{uplink,downlink} convention satisfies this, and the SDK
builds the namespaces for you from the call_sid. If you hand-roll
namespaces, keep them room-scoped. More on the object model in
Sessions, Calls, Tracks & Streams.Where the call_sid comes from
You attach a bridge to a call you already have. For an outbound call you get the
call_sid back from voice.calls.originate. For inbound calls, drive the leg to
your bridge instead of the built-in runtime by pointing the trunk’s inbound rule
at your integration, then attach as each call lands. The
telephony transport section
covers trunk routing.
Route 3 — the LiveKit-compatible shim
If your runtime is a browser LiveKit app, thelivekit-compat shim exposes a
livekit-client-shaped surface (Room, RoomEvent, tracks, participants)
mapped onto our MoQT/QUIC transport. For the core voice path — publish the mic,
subscribe to remote audio, exchange data messages — migration is a one-line
import swap, with no SFU and no ICE.
Preview. The
livekit-compat shim is experimental and audio-first — it
covers the core voice path but is not yet a drop-in for every livekit-client
API, and video/screenshare are deferred. It ships for the browser /
TypeScript client today; there is no server-side Python equivalent yet.
Pin a version and test your flows. The full walkthrough, including the
RTCRtpScriptTransform requirement and what maps to what, lives in
Keep Your Existing Agent Runtime.Which route?
Vendor bridge
Your runtime is LiveKit/Vapi/Twilio orchestration. Config-only; you run
the external sidecar.
Raw MoQT bridge
Custom or non-browser runtime, or a server-side loop. Most control, fully
shipped, every SDK.
LiveKit-compat shim
A browser LiveKit app you want to move with minimal edits. Preview.
Related
Keep Your Existing Runtime
The full browser story: the shim, the transport primitives, and the codec
tap that moves an existing WebRTC pipeline onto QUIC.
BYO Speech-to-Speech
Keep our runtime and point it at your own realtime endpoint with
per-tenant credentials.
Agent Runtime Overview
What the managed runtime does when you want us to drive the conversation.
From Self-Hosted LiveKit
The end-to-end migration path for a LiveKit deployment moving onto our
transport.