You connect once. Everything that you build uses 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 that you need. You never wire a second transport, a second auth scheme, or a second reconnect loop. This page shows what sits under that connection and where each piece runs.

The shape

Every method that you call lands on a single MoQT client. The MoQT client sits on top of the C++ core. The core 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. Every layer below is shared across every language and every modality.

How your data moves: MoQT tracks

Everything that you publish reduces to MoQT tracks. Because of this, you never manage delivery yourself. You name a track by (namespace, name). You attach a capability tag. You write frames. The relay fans the track out to every subscriber that matched the namespace + capability. You do not know who subscribed. A subscriber does not know who you are. You can add or drop consumers at any time. Your publish code never changes. Subgroup streams give in-order, reliable delivery per group. Datagrams trade ordering for a sub-millisecond floor. You do not choose by hand. The modality picks the correct lane per channel for you. See each modality’s concept page.

The relay mesh

The relay makes your fan-out scale. You do not tune anything. The relay is the same binary as the engine, with the built-in relay role enabled. It runs shard-per-core: one shard per core. Each shard binds the same UDP port with SO_REUSEPORT. An in-kernel classifier 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 for three reasons. The relay’s data path is zero-copy where the QUIC sequencer allows. It is GSO-batched on send. It uses UDP_GRO on receive. There are no per-hop copies when your track fans out. You can address POPs by DNS round-robin under relay.clutchcall.dev. You can also address each edge by its POP code (relay-us.clutchcall.dev, relay-uk.clutchcall.dev, …).

Two ports, two stacks

The relay runs two QUIC stacks on two ports. It does not multiplex on one port: You do not pick a port. Your SDK finds the correct port through RFC 9460 HTTPS records. The split keeps each stack’s SO_REUSEPORT DCID dispatch intact. It also avoids the ~300-500 LOC of userspace ALPN-sniffed routing that single-port multiplexing would need.

Why every language behaves the same

You get identical wire behavior and identical latency in every language, because one core sits under all of them. Two results follow from that. Identical wire envelopes. The relay sees the same MoQT framing from every SDK. A message that you send from Python looks the same as one from Rust. There is no per-language parser to keep in sync. There is only the C++ core, which every SDK imports via FFI / WASM. Audio without a copy. The core does µ-law / A-law to 16-bit PCM conversion in SIMD. Your voice path stays fast everywhere. Browser (WASM) and Node / Python / Go / Rust / Java / .NET (native FFI) call the same code path with the same latency profile.

What happens when you connect

You call connect once. The SDK then does these steps:
  1. Connect. The SDK dials MoQT on relay.clutchcall.dev:443 over QUIC (or WebTransport in the browser). The SDK presents your tenant token as the first MoQT envelope.
  2. Handshake. The relay’s namespace_auth hook checks 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 do not write reconnect logic. If the link drops, the SDK reconnects with capped exponential backoff. It re-establishes every publication and subscription transparently. Your application code never sees the reconnect.
The same client also gives you a control plane. 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 internally holds a MoQT client (data plane) and an HTTPS client (control plane). You talk to only one object.

Where your SDK runs

The same core ships everywhere that you deploy. 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 clutchcall_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.clutchcall.transport UPM package exposes INetworkInterface over the games modality. It is a 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 it publishes the SDP answer that points 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. Thus the same call_sid can take either RTP path. The path depends on default_app.

Legacy RPC (still supported)

The original control plane was a method-id RPC envelope over QUIC:
ClutchCallClient (dial, originate_bulk, hangup, barge, push_audio, …) used this surface. It is kept for backwards compat. New code should use the Voice modality. See Envelope Format for the full wire detail.

Code generation

One IDL keeps the SDKs in lockstep across languages. Method IDs and DTO definitions in every language come from one IDL (api/clutchcall.json). A shared IDL code generator compiles it. The modality clients’ wire formats are generated from that same IDL. A new modality method needs only an IDL edit plus a compiler run. It then lands in every language at once.