The streams modality exposes two surfaces from the same subpath import:
  • Control plane — a Streams client over HTTPS that manages live inputs, signing keys, and (preview) assets/API-keys/analytics.
  • Data planeBroadcastPublisher and BroadcastViewer, which move CMAF segments over the persistent MoQT connection.

Import

Control plane — Streams

The control-plane client is stateless HTTPS. Every call is one query or mutation against the control-plane API. The persistent QUIC connection lives in the publisher/viewer, not here.
string
required
Control-plane origin (no trailing slash needed). Python: base_url.
string
required
API key with streams:* scopes, sent as Authorization: Bearer. Python: api_key.
string
Default org/tenant id for every tenant-scoped call. Required for liveInputs.* and signingKeys.*. Python: org_id.
typeof fetch
(TS only) Override fetch for test fakes or custom transports. Defaults to globalThis.fetch.
The client gives you scoped helpers. You never call the transport directly:

liveInputs

Promise<LiveInputWithSecret>
Create a live input. ingest is one of fmp4 (default) | whip | rtmp | srt. Returns { input, streamKey }. The API returns the cleartext streamKey only here (and on rotateStreamKey). Python: create(name=, ingest=) returning LiveInputWithSecret(input, stream_key).
Promise<LiveInput>
Fetch a live input by id. Python: get(id=).
Promise<LiveInput[]>
List inputs (default page=1, perPage=50). Python: list(page=, per_page=).
A LiveInput handle carries snapshot fields and bound methods:
string
The path segment used in publish/playback URLs (the <input_id>).
'idle' | 'live' | 'errored'
Current ingest state.
Promise<SignedPlaybackUrl>
Mint a signed playback URL (?tok=<jwt> attached). The server clamps ttlSeconds to 30 s – 24 h (default 3600). Returns { url, kid, alg, expiresAt }. Python: signed_playback_url(ttl_seconds=).
Promise<LiveInputWithSecret>
Rotate the stream key. Returns a fresh cleartext streamKey. The API returns it only once. Python: rotate_stream_key().

signingKeys

The org’s playback signing keys. One of these keys signs each playback JWT. The kid header on each token names the key.
Promise<SigningKey>
Create a signing key. alg is Ed25519 (default) | RS256. use is playback. Returns a SigningKey with { id, alg, publicKeyPem, status }. Python: create(alg=, use=).
Promise<SigningKey[]>
List the org’s signing keys.
Promise<void>
Deactivate a key. Existing tokens minted from it stop verifying.
The control-plane API also exposes asset management, API-key administration, and viewer analytics (overview KPIs, viewer time-series, glass-to-glass latency histograms, edge-POP health). These use the same streams.* route shape as the typed helpers above. Dedicated typed helpers (streams.assets.*, streams.apiKeys.*, streams.analytics.*) are rolling out. Until they land in your SDK version, call the control-plane API directly with the same CLUTCHCALL_CREDENTIALS bearer key. Treat these surfaces as Preview.

Data plane — BroadcastPublisher

Send a broadcast into a live input over MoQT. The per-input stream key authorizes it. The TypeScript publisher fragments a browser MediaStream to CMAF. The Python publisher takes raw CMAF chunks that you supply (server-side packaging).

TypeScript surface

BroadcastPublisher
Construct a publisher. opts: mimeType? (MediaRecorder mime, default video/mp4; codecs="avc1.42E01E,mp4a.40.2"), timesliceMs? (fragment cadence, default 1000), serverCertificateHash?, webTransport?, onError?.
Promise<void>
Connect to /publish/<input>?sk=<streamKey>, announce the track, and stream CMAF fragments from media (a MediaStream). namespace is the MoQ namespace that the relay expects (stream/<org>/<input>).
void
Stop recording, close the track, and close the session.

Python surface

BroadcastPublisher
Open a publisher. Args: input_id, stream_key, relay_host?, codecs? (PublisherCodecs(video=, audio=)), on_close?.
None
Send one CMAF chunk. The first chunk is the init segment (priority 0, opens a group). Subsequent chunks are media (priority 1). Pass timestamp_us to override the monotonic timestamp (replay/tape-sync).
None
Close the publisher. reasonclosed_by_caller (default) | auth_failed | network | finished.

Data plane — BroadcastViewer

Play a stream from a playback id (TS, browser <video>) or from a signed playback URL (Python, chunk callback).

TypeScript surface

BroadcastViewer
Construct a viewer. Data-plane Streams opts: apiBase? (resolve/catalog base), relayUrl?, token? (signed JWT, carried as ?tok=), serverCertificateHash?. Per-viewer extra: onStarted?, onError?, webTransport?, fetchImpl?.
this
Attach the <video> element the stream renders into. Chainable.
Promise<void>
Resolve and play. lv_* plays live over MoQT. It subscribes to the .catalog track in-band, then to media tracks. pb_* plays VOD over HTTPS from the catalog.
void
Close every track subscription and end the MediaSource.

Python surface

BroadcastViewer
Connect to a signed moq://…/playback/<input>?tok=<jwt> URL and forward chunks. on_chunk(is_init, chunk) fires per segment. The first segment has is_init=True. chunk is a BroadcastChunk(data, timestamp_us, priority, is_init).
None
Close the session. This fires on_close("closed_by_caller", None).

Events & close reasons

Both surfaces report terminal state through callbacks rather than an emitter:
callback
(Viewer) Playback started. The first segment is buffered.
callback
Connection or decode error. If you set no handler, errors throw from play() / publish().
callback (Python)
Terminal close. reasoncomplete | auth_failed | network | closed_by_caller. An expired/invalid playback JWT yields auth_failed.
Other languages. The streams surface mirrors across the polyglot SDKs. The control-plane Streams client, BroadcastPublisher, and BroadcastViewer keep the same method names (camelCase in TS, snake_case in Python and the others). The TypeScript and Python signatures above are the reference shapes.

Types reference

Helpers: parseCatalog(json), mseType(track), videoTrack(cat), audioTrack(cat).