# Stream Live Streaming API

Live input creation, status checking, simulcast, and WebRTC streaming.

## Create Live Input

### Using Cloudflare SDK

```typescript
import Cloudflare from "cloudflare";

const client = new Cloudflare({ apiToken: env.CF_API_TOKEN });

const liveInput = await client.stream.liveInputs.create({
  account_id: env.CF_ACCOUNT_ID,
  recording: { mode: "automatic", timeoutSeconds: 30 },
  deleteRecordingAfterDays: 30,
});

// Returns: { uid, rtmps, srt, webRTC }
```

### Raw fetch API

```typescript
async function createLiveInput(accountId: string, apiToken: string) {
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/accounts/${accountId}/stream/live_inputs`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${apiToken}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        recording: { mode: "automatic", timeoutSeconds: 30 },
        deleteRecordingAfterDays: 30,
      }),
    }
  );
  const { result } = await response.json();
  return {
    uid: result.uid,
    rtmps: { url: result.rtmps.url, streamKey: result.rtmps.streamKey },
    srt: { url: result.srt.url, streamId: result.srt.streamId, passphrase: result.srt.passphrase },
    webRTC: result.webRTC,
  };
}
```

## Check Live Status

```typescript
async function getLiveStatus(accountId: string, liveInputId: string, apiToken: string) {
  const response = await fetch(
    `https://api.cloudflare.com/client/v4/accounts/${accountId}/stream/live_inputs/${liveInputId}`,
    { headers: { Authorization: `Bearer ${apiToken}` } }
  );
  const { result } = await response.json();
  return {
    isLive: result.status?.current?.state === "connected",
    recording: result.recording,
    status: result.status,
  };
}
```

## Simulcast (Live Outputs)

### Create Output

```typescript
async function createLiveOutput(
  accountId: string,
  liveInputId: string,
  apiToken: string,
  outputUrl: string,
  streamKey: string
) {
  return fetch(
    `https://api.cloudflare.com/client/v4/accounts/${accountId}/stream/live_inputs/${liveInputId}/outputs`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${apiToken}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        url: `${outputUrl}/${streamKey}`,
        enabled: true,
        streamKey, // For platforms like YouTube, Twitch
      }),
    }
  ).then(r => r.json());
}
```

### Example: Simulcast to YouTube + Twitch

```typescript
const liveInput = await createLiveInput(accountId, apiToken);

// Add YouTube output
await createLiveOutput(
  accountId,
  liveInput.uid,
  apiToken,
  "rtmp://a.rtmp.youtube.com/live2",
  "your-youtube-stream-key"
);

// Add Twitch output
await createLiveOutput(
  accountId,
  liveInput.uid,
  apiToken,
  "rtmp://live.twitch.tv/app",
  "your-twitch-stream-key"
);
```

## WebRTC Streaming (WHIP/WHEP)

### Browser to Stream (WHIP)

```typescript
async function startWebRTCBroadcast(liveInputId: string) {
  const pc = new RTCPeerConnection();

  // Add local media tracks
  const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
  stream.getTracks().forEach(track => pc.addTrack(track, stream));

  // Create offer
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);

  // Send to Stream via WHIP
  const response = await fetch(
    `https://customer-<CODE>.cloudflarestream.com/${liveInputId}/webRTC/publish`,
    {
      method: "POST",
      headers: { "Content-Type": "application/sdp" },
      body: offer.sdp,
    }
  );

  const answer = await response.text();
  await pc.setRemoteDescription({ type: "answer", sdp: answer });
}
```

### Stream to Browser (WHEP)

```typescript
async function playWebRTCStream(videoId: string) {
  const pc = new RTCPeerConnection();

  pc.addTransceiver("video", { direction: "recvonly" });
  pc.addTransceiver("audio", { direction: "recvonly" });

  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);

  const response = await fetch(
    `https://customer-<CODE>.cloudflarestream.com/${videoId}/webRTC/play`,
    {
      method: "POST",
      headers: { "Content-Type": "application/sdp" },
      body: offer.sdp,
    }
  );

  const answer = await response.text();
  await pc.setRemoteDescription({ type: "answer", sdp: answer });

  return pc;
}
```

## Recording Settings

| Mode             | Behavior                                     |
| ---------------- | -------------------------------------------- |
| `automatic`      | Record all live streams                      |
| `off`            | No recording                                 |
| `timeoutSeconds` | Stop recording after N seconds of inactivity |

```typescript
const recordingConfig = {
  mode: "automatic",
  timeoutSeconds: 30, // Auto-stop 30s after stream ends
  requireSignedURLs: true, // Require token for VOD playback
  allowedOrigins: ["https://yourdomain.com"],
};
```

## In This Reference

- [README.md](./README.md) - Overview and quick start
- [api.md](./api.md) - On-demand video APIs
- [configuration.md](./configuration.md) - Setup and config
- [patterns.md](./patterns.md) - Full-stack flows, best practices
- [gotchas.md](./gotchas.md) - Error codes, troubleshooting

## See Also

- [workers](../workers/) - Deploy live APIs in Workers
