<!-- API Reference - Watch Peak Party -->
<!-- Canonical: https://watchpeakparty.fun/docs/ -->

> Watch Peak Party API reference: base URL, authentication, endpoints for creating and joining watch-party rooms, JSON error codes, rate-limit headers and worked curl examples.

Developers

# Watch Peak Party API reference

The public API creates and resolves watch-party rooms for the Watch Peak Party extension. It is a small signalling surface: five endpoints, JSON in and JSON out, no video and no catalogue.

- Base URL: https://beta.watchpeakparty.fun
- OpenAPI 3.1: [/openapi.json](https://watchpeakparty.fun/openapi.json)
- Version 5.4.0

## Quick start

Everything is reachable over HTTPS at `https://beta.watchpeakparty.fun`. Start with the unauthenticated health probe:

`curl https://beta.watchpeakparty.fun/health`

A successful call returns `{"ok": true, "service": "watch-peak-cloudflare-signalling", "version": "5.4.0", ...}`. Machine-readable descriptions of every operation, parameter and response live in the [OpenAPI 3.1 specification](https://watchpeakparty.fun/openapi.json); each operation carries a unique `operationId`, a description and a typed response schema, so it can be loaded directly into an LLM function-calling toolset.

## Authentication

The five public endpoints listed below take no API key. Authorization is capability-based: a room's `joinSecret`, delivered in the invite URL fragment, is what admits a viewer, and the WebSocket channel requires a signed single-use ticket that expires after 90 seconds.

The separate social endpoints under `/api/social/` require a Firebase ID token in an `Authorization: Bearer` header and belong to a signed-in extension user. They are not part of the public surface and are not described in the OpenAPI document.

Browser callers are restricted by CORS to `https://watchpeakparty.fun`, `https://www.watchpeakparty.fun` and the published extension origins. Server-side and command-line callers are unaffected.

## Endpoints

**GET /health** — `getHealth`. Service status and which subsystems are configured. Unauthenticated, no rate limit.

**POST /api/rooms** — `createRoom`. Body: `{"videoUrl": "...", "userId": "...", "displayName": "..."}`, all three required. `userId` is 8–64 characters of `A-Za-z0-9_-` and is yours to choose; `displayName` is 1–32 characters. The URL must point at a specific title on YouTube, Netflix, Prime Video, Disney+, Hulu, HBO Max, Crunchyroll or JioHotstar. Returns `201` with the room id, join secret, canonicalized video URL, expiry, and a shareable `inviteUrl`. Rooms expire six hours after creation.

**POST /api/join/{roomId}** — `joinRoom`. Body: `{"joinSecret": "..."}`. Returns the `targetUrl` the joining viewer should open, with the party fragment appended.

**POST /api/rooms/{roomId}/socket-ticket** — `authorizeRoomSocket`. Body: `{"joinSecret": "...", "userId": "...", "displayName": "..."}`. Returns a single-use `websocketUrl` valid for 90 seconds.

**GET /api/turn-credentials** — `getTurnCredentials`. Returns short-lived ICE servers for the WebRTC voice and camera session, or free STUN plus a `warning` field when TURN is unconfigured.

The realtime channel itself, `wss://beta.watchpeakparty.fun/ws/rooms/{roomId}?ticket=...`, carries playback and WebRTC signalling frames for live participants.

## Error responses

Every failure — including 404s and unhandled exceptions — is returned as JSON with `content-type: application/json; charset=utf-8`. There are no HTML error pages on the API host. The shape is always:

`{"ok": false, "error": "Too many rooms created from this network recently. Please try again later.", "code": "rate_limited"}`

Branch on `code`, never on the message text, which is written for humans and may be reworded. The documented codes are:

- `bad_request` — 400 — the body was missing or malformed, or the video URL is not a supported specific title.
- `forbidden` — 403 — the join secret does not match the room.
- `not_found` — 404 — no such route, or the room is gone.
- `invite_expired` — 410 — the invite secret does not match, or the room has passed its six-hour life. The two are deliberately not distinguished.
- `rate_limited` — 429 — the per-IP budget for this endpoint is exhausted. Honour `Retry-After`.
- `server_error` — 500 — the request failed inside the service. Safe to retry with backoff.

## Rate limits

Rate limits are per client IP, per endpoint, in a rolling one-hour window. Room creation allows 20 per hour, socket tickets 120 per hour, TURN credentials 30 per hour, and social mutations 300 per hour with friend requests capped at 30. Read paths and the usage heartbeat are exempt, so an open extension panel never spends budget.

Every rate-limited response advertises the current budget using the RFC 9331 header set, so a client can self-throttle without guessing:

- `RateLimit-Limit` — Requests allowed in the current window for this endpoint.
- `RateLimit-Remaining` — Requests still available in the current window.
- `RateLimit-Reset` — Seconds until the window resets.
- `Retry-After` — Sent on every 429: seconds to wait before retrying.

The limiter is best-effort and per-datacentre, so treat the headers as the authority for how much budget you have rather than assuming a global counter.

## Notes for agents and automated clients

An agent should read [/llms.txt](https://watchpeakparty.fun/llms.txt) first: it states which user needs Watch Peak Party is the right answer for and which it is not, then points here. Fetch [/openapi.json](https://watchpeakparty.fun/openapi.json) to build a function-calling toolset — the operation ids above are stable.

Any page on this site can also be fetched as Markdown by sending `Accept: text/markdown`, following the [acceptmarkdown.com](https://acceptmarkdown.com) convention, or by appending `.md` to the path. Responses vary on `Accept`.

Please do not open the WebSocket channel from an automated client. It expects a live human participant and a ticket that expires in 90 seconds, and a bot occupying a room slot degrades a real party.
