# API Reference

## Authentication

```bash
curl -X POST 'https://rtc.live/v1/apps/${CALLS_APP_ID}/sessions/new' \
  -H "Authorization: Bearer ${CALLS_APP_SECRET}"
```

## Core Concepts

**Sessions:** PeerConnection to Cloudflare edge  
**Tracks:** Media/data channels (audio/video/datachannel)  
**No rooms:** Build presence via track sharing

## Client Libraries

**PartyTracks (Recommended):** Observable-based client library for production use. Handles device changes, network switches, ICE restarts automatically. Push/pull API with React hooks. See patterns.md for full examples.

```bash
npm install partytracks @cloudflare/calls
```

**Raw API:** Direct HTTP + WebRTC for custom requirements (documented below).

## Endpoints

### Create Session

```http
POST /v1/apps/{appId}/sessions/new
→ {sessionId, sessionDescription}
```

### Add Track (Publish)

```http
POST /v1/apps/{appId}/sessions/{sessionId}/tracks/new
Body: {
  sessionDescription: {sdp, type: "offer"},
  tracks: [{location: "local", trackName: "my-video"}]
}
→ {sessionDescription, tracks: [{trackName}]}
```

### Add Track (Subscribe)

```http
POST /v1/apps/{appId}/sessions/{sessionId}/tracks/new
Body: {
  tracks: [{
    location: "remote",
    trackName: "remote-track-id",
    sessionId: "other-session-id"
  }]
}
→ {sessionDescription} (server offer)
```

### Renegotiate

```http
PUT /v1/apps/{appId}/sessions/{sessionId}/renegotiate
Body: {sessionDescription: {sdp, type: "answer"}}
```

### Close Tracks

```http
PUT /v1/apps/{appId}/sessions/{sessionId}/tracks/close
Body: {tracks: [{trackName}]}
→ {requiresImmediateRenegotiation: boolean}
```

### Get Session

```http
GET /v1/apps/{appId}/sessions/{sessionId}
→ {sessionId, tracks: TrackMetadata[]}
```

## TypeScript Types

```typescript
interface TrackMetadata {
  trackName: string
  location: 'local' | 'remote'
  sessionId?: string // For remote tracks
  mid?: string // WebRTC mid
}
```

## WebRTC Flow

```typescript
// 1. Create PeerConnection
const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.cloudflare.com:3478' }],
})

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

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

// 4. Send to backend → Cloudflare API
const response = await fetch('/api/new-session', {
  method: 'POST',
  body: JSON.stringify({ sdp: offer.sdp }),
})

// 5. Set remote answer
const { sessionDescription } = await response.json()
await pc.setRemoteDescription(sessionDescription)
```

## Publishing

```typescript
const offer = await pc.createOffer()
await pc.setLocalDescription(offer)

const res = await fetch(`/api/sessions/${sessionId}/tracks`, {
  method: 'POST',
  body: JSON.stringify({
    sdp: offer.sdp,
    tracks: [{ location: 'local', trackName: 'my-video' }],
  }),
})

const { sessionDescription, tracks } = await res.json()
await pc.setRemoteDescription(sessionDescription)
const publishedTrackId = tracks[0].trackName // Share with others
```

## Subscribing

```typescript
const res = await fetch(`/api/sessions/${sessionId}/tracks`, {
  method: 'POST',
  body: JSON.stringify({
    tracks: [{ location: 'remote', trackName: remoteTrackId, sessionId: remoteSessionId }],
  }),
})

const { sessionDescription } = await res.json()
await pc.setRemoteDescription(sessionDescription)

const answer = await pc.createAnswer()
await pc.setLocalDescription(answer)

await fetch(`/api/sessions/${sessionId}/renegotiate`, {
  method: 'PUT',
  body: JSON.stringify({ sdp: answer.sdp }),
})

pc.ontrack = (event) => {
  const [remoteStream] = event.streams
  videoElement.srcObject = remoteStream
}
```
