# TypeScript Reference

> Every modality, every method, every option.

The TypeScript SDK ships **five modality sub-imports** plus a raw MoQT client
and a legacy RPC client. Each sub-import is its own client class with its own
options.

```ts
import { Voice }      from "@clutchcall/sdk/voice";
import { Streams }    from "@clutchcall/sdk/streams";
import { Robotics }   from "@clutchcall/sdk/robotics";
import { Games }      from "@clutchcall/sdk/games";
import { Data }       from "@clutchcall/sdk/data";
import { MoqtClient } from "@clutchcall/sdk/moqt";
```

## Voice

```ts
const v = new Voice({
  baseUrl:        "https://app.clutchcall.dev",   // control-plane API base
  apiKey?:        string,    // server-side
  browserToken?:  string,    // browser-side
  orgId?:         string,
});
```

### Calls (control plane)

```ts
await v.calls.originate({
  to:       string,                 // E.164
  from?:    string,                 // E.164
  trunkId?: string,                 // your trunk
  agent?:   string,                 // AI agent name (optional)
}) → Call

await v.calls.get(sid)                          → Call
await v.calls.list({ orgId?, cursor?, limit? }) → { calls, cursor? }
await v.calls.transfer(sid, { to, trunkId? })   → Call
await v.calls.hangup(sid)                       → void
await v.calls.terminate(sid)                    → void
```

`Call` exposes:

```ts
call.sid:    string
call.status: CallStatus
call.from:   string
call.to:     string

call.onStatus((s: CallStatus) => void): Unsubscribe
await call.refresh(): Promise<CallData>
await call.hangup(): Promise<void>
await call.transfer(args): Promise<Call>
```

### AudioBridge (data plane)

```ts
const bridge = await v.audioBridge.attach(callSid, {
  codec:      "opus" | "pcm16" | "g711_ulaw" | "g711_alaw",
  onUplink?:  (frame: Uint8Array, tsUs: bigint) => void,
});

bridge.publishUplink(frame: Uint8Array): void   // browser → cloud
bridge.publishDownlink(frame: Uint8Array): void // cloud → caller
bridge.onUplink(cb): Unsubscribe
bridge.onDownlink(cb): Unsubscribe
await bridge.close(): Promise<void>
```

Browser helpers:

```ts
import { captureMicrophone, OpusPlayer } from "@clutchcall/sdk/voice";

const mic    = await captureMicrophone({ onFrame: f => bridge.publishUplink(f) });
const player = new OpusPlayer();
bridge.onDownlink(f => player.play(f));
```

### Agents

```ts
await v.agents.attach(callSid, agentName): Promise<void>
await v.agents.detach(callSid): Promise<void>
await v.agents.list({ orgId? }): Promise<Agent[]>
```

## Streams

```ts
const streams = new Streams({
  baseUrl:  "https://app.clutchcall.dev",
  apiKey:   string,
  orgId:    string,
});
```

### Control plane

```ts
streams.liveInputs.create({ name, codecs?, recordingProfile? })
                                                → { input, streamKey }   // streamKey returned ONCE
streams.liveInputs.get({ id })                  → LiveInput
streams.liveInputs.list({ orgId, cursor?, limit? }) → { liveInputs, cursor? }
streams.liveInputs.rotateStreamKey({ id })      → { streamKey }
streams.liveInputs.delete({ id })               → void

streams.signingKeys.create({ orgId, label })    → { id, keyMaterial }
streams.signingKeys.list({ orgId })             → SigningKey[]
streams.signingKeys.retire({ id })              → void

streams.apiKeys.create({ orgId, label, scopes }) → { id, secret }       // secret returned ONCE
streams.apiKeys.list({ orgId })                  → ApiKey[]
streams.apiKeys.revoke({ id })                   → void

streams.webhooks.create({ orgId, url, events })  → Webhook
streams.webhooks.list({ orgId })                 → Webhook[]
streams.webhooks.delete({ id })                  → void
streams.events.listDeliveries({ webhookId, cursor?, limit? }) → { deliveries, cursor? }

streams.analytics.viewerMinutes({ orgId, from, to, groupBy? }) → ViewerMinutesRow[]
streams.analytics.popCache({ orgId, from, to })   → PopCacheRow[]
```

`LiveInput` exposes:

```ts
input.external_input_id: string
await input.signedPlaybackUrl({ ttlSeconds: number, scopes? }) → { url, expiresAt }
```

### Data plane

```ts
const pub = await BroadcastPublisher.open({
  inputId:   string,
  streamKey: string,                  // from create() / rotateStreamKey()
  codecs:    { video: string, audio: string },
});
pub.write(chunk: Uint8Array): void
await pub.close(reason?: string): Promise<void>

const viewer = await BroadcastViewer.open(signedUrl, {
  onChunk: (init: BroadcastInit, chunk: BroadcastChunk) => void,
  onClose: (reason: string) => void,
});
await viewer.close(): Promise<void>
```

## Robotics

```ts
const r = new Robotics({
  relayHost: "relay.clutchcall.dev",
  token:     string,
  robotId:   string,        // unique per (tenant, robot)
});
```

```ts
// publish
await r.publishTelemetry({
  topic:    string,                       // e.g. "odom"
  typeName: string,                       // e.g. "nav_msgs/msg/Odometry"
  qos?:     QoSProfile,
}) → RoboticsPublication

await r.publishCommand({
  topic:    string,                       // e.g. "cmd_vel"
  typeName: string,                       // e.g. "geometry_msgs/msg/Twist"
  qos?:     QoSProfile,
}) → RoboticsPublication

// subscribe
await r.subscribeTelemetry({ topic, qos? },
  (payload: Uint8Array, typeName: string) => void) → RoboticsSubscription
await r.subscribeCommand   ({ topic, qos? },
  (payload: Uint8Array, typeName: string) => void) → RoboticsSubscription
```

`RoboticsPublication`:

```ts
pub.write(cdrBytes: Uint8Array): void
await pub.close(): Promise<void>
```

`QoSProfile`:

```ts
{
  reliability?: "reliable" | "best_effort";
  durability?:  "volatile"  | "transient_local";
  depth?:       number;
}
```

## Games

```ts
const g = new Games({
  relayHost: "relay.clutchcall.dev",
  token:     string,
  roomId:    string,
  playerId?: string,        // omit for the authoritative server
});
```

### Player

```ts
g.subscribeState((bytes: Uint8Array) => void): GamesSubscription
const input = await g.publishInput(): FromPublisher
input.write(bytes: Uint8Array): void

const events = await g.publishEvent(): FromPublisher
events.send(obj: any): void
g.subscribeEvents((event: any, fromPlayerId: string) => void): GamesSubscription
```

### Authority (no `playerId`)

```ts
const state = await g.publishState({ tickHz?: number }): StatePublisher
state.write(bytes: Uint8Array): void

await g.subscribeInputs((playerId: string, bytes: Uint8Array) => void): GamesSubscription
await g.subscribeEvents((event: any, fromPlayerId: string) => void): GamesSubscription
```

## Data

```ts
const d = new Data({
  relayHost: "relay.clutchcall.dev",
  token:     string,
  clientId:  string,        // your publisher identity
});
```

```ts
await d.publish({
  topic:     string,
  payload:   Uint8Array,
  reliable?: boolean,                     // default false → datagram
  retain?:   boolean,                     // last-value-stuck
}): void

await d.subscribe({ topicFilter: string }, (msg: DataMessage) => void)
                                                          : DataSubscription
```

`DataMessage`:

```ts
{
  topic:        string;        // the actual topic published to
  payload:      Uint8Array;
  fromClientId: string;
  retain:       boolean;
  tsUs:         bigint;
}
```

Topic filters support MQTT-style `+` (one segment) and `#` (multi-segment,
trailing only).

## Realtime Tracks

The raw substrate. See [Realtime Tracks](/concepts/realtime-tracks) for the
full surface. Common methods:

```ts
const moqt = await MoqtClient.connect(relayUrl, token, onState);

moqt.publishFrame(namespace, name, opts?: FrameOptions): FramePublication
moqt.subscribeFrame(namespace, name, cb): FrameSubscription
moqt.publishAudio(namespace, name, opts?: AudioOptions): AudioPublication
moqt.subscribeAudio(namespace, name, cb): AudioSubscription
moqt.publishVideo(namespace, name, opts?: VideoOptions): VideoPublication
moqt.subscribeVideo(namespace, name, cb): VideoSubscription
moqt.publishText(namespace, name, opts?: TextOptions): TextPublication
moqt.subscribeText(namespace, name, cb): TextSubscription

moqt.subscribeNamespace(prefix: string[],
  (suffix: string, active: boolean) => void): void
moqt.connectionRttUs(): bigint
moqt.maxDatagramSize(): number
moqt.close(): void
```

## Legacy RPC

The root import is the legacy voice-RPC surface (`dial`, `originate_bulk`,
`hangup`, `barge`, `push_audio`, …). Documented for backwards compat — new
code should use the [Voice modality](#voice).

```ts
import { ClutchCallClient } from "@clutchcall/sdk";

const client = new ClutchCallClient("https://pbx.clutchcall.dev");
await client.dial(/* ... */);
await client.hangup(/* ... */);
```

See the [SDK split repo](https://github.com/clutchcall/typescript-sdk) for the
full legacy surface.
