This section documents the legacy voice-RPC wire format. It’s kept for reference and backwards compatibility — new code should use the modality clients over MoQT instead. The Voice modality (clutchcall.voice, @@clutchcall/sdk/voice, etc.) replaces every method_id RPC documented here with a typed surface that runs over the same MoQT relay mesh as streams, robotics, games, and data.See Architecture for how the legacy envelope and MoQT coexist today.
The ClutchCall gateway’s original control plane was a binary RPC protocol over QUIC. The legacy SDK surface (ClutchCallClient.dial, hangup, barge, push_audio, …) wraps it; nothing is hidden. If you have a QUIC client and a serializer for little-endian primitives, you can talk to the gateway directly.

Read these in order

1

Envelope Format

Byte layout of a single RPC frame on the wire — length prefix, method id, serde envelope body, field encoding. → Envelope Format
2

Method IDs

The full table of method_id constants and their request/response DTOs. → Method IDs
3

Types

Field-level breakdown of every DTO (OriginateRequest, CallEvent, etc). → Types
4

Audio Frames

How outbound and inbound AudioFrame envelopes are framed on uni-streams. → Audio Frames
5

Events

Server-pushed CallEvent semantics, ordering, and reconnect behaviour. → Events

Endpoint

quic://engine.clutchcall.dev:9090   (ALPN: h3)
In the browser, the same gateway is reachable via WebTransport:
https://engine.clutchcall.dev:9090

Stream model

Connection setup uses one bidirectional stream for the initial JWT handshake (the SDK does this for you). After that:
Stream typeDirectionCarries
Bidirectionalclient → serverA single RPC envelope; close-on-write
Unidirectionalclient → serverAudioFrame stream (mic → trunk)
Unidirectionalserver → clientCallEvent and AudioFrame (trunk → app)
Every frame, regardless of stream, follows the envelope format.

Versioning

Each serde envelope carries a 1-byte version and a 1-byte compat_version. The gateway accepts envelopes whose compat_version ≤ server_current_version. Adding fields is backwards-compatible; removing or reordering them is not — do that with a new method id, not a version bump.