You connect once, and everything you build rides that one connection. Voice, streams, robotics, games, and data all publish and subscribe over the same QUIC link to the relay mesh, through one typed SDK. You pick the modality you need; you never wire up a second transport, a second auth scheme, or a second reconnect loop. This page shows you what sits under that connection and where each piece runs, so you know what you’re standing on.

The shape

              ┌──────────────────────────────────────────────────┐
              │              Your application code               │
              │     (Python / TS / Go / Rust / Java / .NET /     │
              │                  Unity .NET runtime)             │
              └────────────────────────┬─────────────────────────┘
                                       │ idiomatic methods
              ┌────────────────────────▼─────────────────────────┐
              │            TeleQuick language SDK             │
              │  ┌────────┬────────┬──────────┬───────┬───────┐  │
              │  │ Voice  │Streams │ Robotics │ Games │ Data  │  │
              │  └────────┴────────┴──────────┴───────┴───────┘  │
              │              MoqtClient (substrate)              │
              └────────────────────────┬─────────────────────────┘
                                       │ C ABI: telequick_*
              ┌────────────────────────▼─────────────────────────┐
              │      C++23 core (one binary, all languages)      │
              │  - MoQT framer / parser                          │
              │  - subgroup-stream + datagram scheduler          │
              │  - capability routing + namespace auth           │
              │  - APM pipeline (AEC, AGC2, resampler)           │
              └────────────────────────┬─────────────────────────┘
                                       │ QUIC (UDP/443 + UDP/4433)
              ┌────────────────────────▼─────────────────────────┐
              │             TeleQuick relay mesh              │
              │   Shard-per-core · SO_REUSEPORT + eBPF dispatch  │
              │  Capability-based fan-out · namespace gating     │
              └────────────────────────┬─────────────────────────┘
                                       │ control plane
              ┌────────────────────────▼─────────────────────────┐
              │        TeleQuick engine (per modality)         │
              │  Voice telephony · streams ingest/transcode ·    │
              │  agent runtime · webhook events · analytics      │
              └──────────────────────────────────────────────────┘
Every method you call lands on a single MoQT client, which sits on top of the C++ core, which speaks QUIC to the relay mesh. The relay handles fan-out and capability routing; the engine handles the control plane. You work in idiomatic methods at the top; everything below is shared across every language and every modality.

How your data moves: MoQT tracks

Everything you publish reduces to MoQT tracks, and this is why you never manage delivery yourself. You name a track by (namespace, name), attach a capability tag, and write frames. The relay fans the track out to every subscriber that matched the namespace + capability. You don’t know who’s subscribed; a subscriber doesn’t know who you are. Add or drop consumers at any time — your publish code never changes.
Track kindCarriesWire model
AudioContinuous voice (Opus / PCM / G.711)subgroup stream
VideoEncoded video; group per keyframesubgroup stream
FrameOpaque binary with per-frame prioritysubgroup OR datagram (datagram=true)
TextReliable ordered messagessubgroup stream
Subgroup streams give you in-order, reliable delivery per group; datagrams trade ordering for a sub-millisecond floor. You don’t choose by hand — the modality picks the right lane per channel for you. See each modality’s concept page.

The relay mesh

The relay is what makes your fan-out scale without you tuning anything. It’s the same binary as the engine, with the built-in relay role enabled, and it runs shard-per-core: one shard per core, each shard binds the same UDP port with SO_REUSEPORT and an eBPF program dispatches incoming QUIC packets to the shard that owns the connection’s destination CID. Each shard:
  • accepts QUIC handshakes (ECDSA P-256)
  • maintains its share of MoQT sessions
  • forwards published frames to subscribers without leaving the shard
  • gates each publish/subscribe through the namespace auth hook (JWT verify with namespace-scoped claims)
Your frames stay low-latency at scale because the relay’s data path is zero-copy where the QUIC sequencer allows, GSO-batched on send, and UDP_GRO on receive — no per-hop copies as your track fans out. POPs are addressable by DNS round-robin under relay.telequick.dev and by the per-edge POP code (relay-us.telequick.dev, relay-uk.telequick.dev, …).

Two ports, two stacks

The relay runs two QUIC stacks on two ports rather than multiplexing on one:
PortStackCarries
443QUIC · MoQTMoQT (audio / video / frame / text tracks)
4433QUIC · HTTP/3HTTP/3 + WebTransport (REST, MCP, signalling)
You don’t pick a port — your SDK finds the right one via RFC 9460 HTTPS records. The split keeps each stack’s SO_REUSEPORT + eBPF DCID dispatch intact and avoids the ~300-500 LOC of userspace ALPN-sniffed routing single-port multiplexing would need.

Why every language behaves the same

Whatever language you build in, you get identical wire behavior and identical latency — because there’s one core underneath all of them. Two things follow from that. Identical wire envelopes. The relay only ever sees the same MoQT framing regardless of which SDK published, so a message you send from Python looks the same as one from Rust. There’s no per-language parser to keep in sync — only the C++ core, which every SDK imports via FFI / WASM. Audio without a copy. µ-law / A-law to 16-bit PCM conversion is done in SIMD inside the core, so your voice path stays fast everywhere. Browser (WASM) and Node / Python / Go / Rust / Java / .NET (native FFI) call into the same code path with the same latency profile.

What happens when you connect

You call connect once; here’s what the SDK does for you underneath.
  1. Connect. The SDK dials MoQT on relay.telequick.dev:443 over QUIC (or WebTransport on browser). Your tenant token is presented as the first MoQT envelope.
  2. Handshake. The relay’s namespace_auth hook verifies the token and stamps a namespace scope on the session.
  3. Publish / subscribe. The SDK opens MoQT publish and subscribe requests on demand. The relay routes by namespace and capability.
  4. Auto-reconnect. You don’t write reconnect logic. If the link drops, the SDK reconnects with capped exponential backoff and re-establishes every publication and subscription transparently. Your application code never sees it.
You also get a control plane for free on the same client: call originate, live-input create, room token mint, and similar operations run over HTTP/3 on port 4433 as control-plane (tRPC) procedures on the engine. Each modality client holds both a MoQT client (data plane) and an HTTPS client (control plane) under the hood, so you only ever talk to one object.

Where your SDK runs

The same core ships everywhere you deploy, so you get the same behavior on every runtime.
  • Browsers. The TypeScript SDK speaks MoQT directly over native WebTransport (no FFI, no custom framing). The C++ core is compiled to WebAssembly via Emscripten for audio APM + framing fast paths.
  • Native runtimes. The SDK loads telequick_core_ffi.so / .dylib / .dll via the language’s native loader: JNI (Java), P/Invoke (.NET), CGO (Go), libloading (Rust), ctypes (Python).
  • Unity. The .NET runtime SDK plus a com.telequick.transport UPM package exposes INetworkInterface over the games modality — drop-in for Unity Netcode for GameObjects / Entities. See Netcode (Unity).

Direct-media (voice)

When you run a server-side AI call (default_app=AI_BIDIRECTIONAL_STREAM), your audio takes the shortest path: the voice path uses direct-media between the carrier and the agent runtime. The gateway negotiates SIP signalling with the carrier, then publishes the SDP answer pointing at the agent runtime’s RTP socket; RTP flows straight from the carrier to the runtime. The gateway is signalling-only on that path. For SIP/RTP-only calls (no AI bridge), the gateway still terminates RTP and runs a local VAD. So the same call_sid can take either RTP path depending on default_app.

Legacy RPC (still supported)

The original control plane was a method-id RPC envelope over QUIC:
+----------------+----------------+----------------------+
| u32 length LE  | u32 method_id  | serde envelope body  |
+----------------+----------------+----------------------+
TeleQuickClient (dial, originate_bulk, hangup, barge, push_audio, …) used this surface. It’s kept for backwards compat; new code should use the Voice modality. See Envelope Format for the full wire detail.

Code generation

This is why the SDKs stay in lockstep for you across languages: method IDs and DTO definitions in every language come from one IDL (api/telequick.json), compiled by a shared IDL code generator. The modality clients’ wire formats are generated from that same IDL, so a new modality method only needs an IDL edit plus a compiler run — and it lands in every language at once.