cloudflare
references/realtime-sfu/api.md
.md 159 lines
Content
# 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;
};
```