Four endpoints,
one YAML to drive them.
Every field, parameter, response shape, and error envelope below is rendered from /openapi/streams.yaml — edit the spec and this page re-renders in the same change. Auth uses the cookie set by better-auth at /api/auth/sign-up/email; swap in better-auth.session_token=<your-session-cookie> and the curls below land on your local instance.
https://streamwake.app — Read the auth guide.Four operations, straight from the spec.
Section order matches /openapi/streams.yaml#paths. Each card below carries the method, endpoint template, summary, and description pulled directly from the spec.
/streamsRegister a stream (idempotent by sourceUrl)
Upsert a stream by its sourceUrl. The handler validates the body with zod (StreamCreate), runs the SSRF guard against sourceUrl, then upserts by sourceUrl — POST is idempotent, so re-posting the same URL returns the existing record instead of 409. A fresh row is initialized with agentState "healthy", status "watching", lastAction "registered", and uptimePct 100 (a placeholder until the first probe lands).
POST body, field by field
Content type: application/json — schema: StreamCreate
{
"sourceUrl": "https://example.com/manifest.m3u8",
"name": "Primary CDN — eu-west",
"targetRegion": "eu-west"
}curl -X POST https://streamwake.polsia.io/streams \
-H "content-type: application/json" \
-b "better-auth.session_token=<your-session-cookie>" \
-d '{
"sourceUrl": "https://example.com/manifest.m3u8",
"name": "Primary CDN — eu-west",
"targetRegion": "eu-west"
}'{
"id": "ckq3xstreamabc123",
"sourceUrl": "https://example.com/manifest.m3u8",
"name": "Primary CDN — eu-west",
"targetRegion": "eu-west",
"createdAt": "2026-08-03T18:24:11.000Z",
"agentState": "healthy",
"status": "watching",
"lastAction": "registered",
"lastCheckedAt": null,
"uptimePct": 100
}{
"errors": {
"sourceUrl": "Must be a valid URL"
}
}{
"error": "Unauthorized"
}{
"error": "Internal Server Error"
}/streamsList the 50 most recently created streams
Returns the 50 most recently created streams, ordered by createdAt descending. Each row carries the StreamItem shape used by POST, with uptimePct computed server-side from the last 24 hours of StreamProbe rows. Rows with no probes in the window render as 100 — the placeholder the dashboard's StreamRowCard uses.
curl https://streamwake.polsia.io/streams \
-b "better-auth.session_token=<your-session-cookie>"{
"items": [
{
"id": "ckq3xstreamabc123",
"sourceUrl": "https://example.com/manifest.m3u8",
"name": "Primary CDN — eu-west",
"targetRegion": "eu-west",
"createdAt": "2026-08-03T18:24:11.000Z",
"agentState": "healthy",
"status": "watching",
"lastAction": "registered",
"lastCheckedAt": "2026-08-03T18:25:00.000Z",
"uptimePct": 100
},
{
"id": "ckq3xstreamdef456",
"sourceUrl": "https://backup.example.com/manifest.m3u8",
"name": "Backup CDN — eu-west",
"targetRegion": "eu-west",
"createdAt": "2026-08-02T11:02:08.000Z",
"agentState": "degraded",
"status": "degraded",
"lastAction": "raised the latency budget and re-probed to confirm the trend",
"lastCheckedAt": "2026-08-03T18:25:00.000Z",
"uptimePct": 96
}
]
}{
"error": "Unauthorized"
}{
"error": "Internal Server Error"
}/streams/{id}Read one stream's status
Returns the live StreamStatus for one stream. The uptimePct value is computed from the same 24-hour probe window the list endpoint uses, so the detail and list numbers always agree. Returns 404 with { "error": "Not Found" } if the id is unknown.
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | Stable row identifier (cuid). |
curl https://streamwake.polsia.io/streams/<id> \
-b "better-auth.session_token=<your-session-cookie>"{
"id": "ckq3xstreamabc123",
"sourceUrl": "https://example.com/manifest.m3u8",
"agentState": "healthy",
"uptimePct": 100,
"lastAction": "registered",
"lastCheckedAt": "2026-08-03T18:25:00.000Z"
}{
"error": "Unauthorized"
}{
"error": "Not Found"
}{
"error": "Internal Server Error"
}/streams/{id}Update a stream
Update the mutable fields of an existing stream — name and targetRegion. sourceUrl is the stable identity of the row, so it cannot be changed here (re-register the new URL as a separate row). PATCH semantics: fields omitted from the body are left unchanged on the row. Idempotent — repeated PATCHes with the same body return the same row. Returns the updated StreamItem.
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string | Stable row identifier (cuid). |
PATCH body, field by field
Content type: application/json — schema: StreamCreate
{
"name": "Primary CDN — eu-west (renamed)",
"targetRegion": "eu-central"
}curl -X PATCH https://streamwake.polsia.io/streams/<id> \
-H "content-type: application/json" \
-b "better-auth.session_token=<your-session-cookie>" \
-d '{
"name": "Primary CDN — eu-west (renamed)",
"targetRegion": "eu-central"
}'{
"id": "ckq3xstreamabc123",
"sourceUrl": "https://example.com/manifest.m3u8",
"name": "Primary CDN — eu-west (renamed)",
"targetRegion": "eu-central",
"createdAt": "2026-08-03T18:24:11.000Z",
"agentState": "healthy",
"status": "watching",
"lastAction": "registered",
"lastCheckedAt": "2026-08-03T18:25:00.000Z",
"uptimePct": 100
}{
"errors": {
"name": "String must contain at most 120 character(s)"
}
}{
"error": "Unauthorized"
}{
"error": "Not Found"
}{
"error": "Internal Server Error"
}Every body, pulled from the spec.
Consolidated across all four endpoints — one row per distinct (status, body-shape) pair declared in /openapi/streams.yaml. Bodies are emitted by the route handlers in production — copy these bytes when you write your error handler.
| Status | Body | When |
|---|---|---|
400 | | Zod validation failed on the request body, or the SSRF guard refused sourceUrl (loopback / RFC 1918 / link-local). |
401 | | No session cookie, or the cookie is expired. Re-auth via /api/auth/sign-in/email and retry. |
500 | | Unexpected server error — safe to retry. |
404 | | Returned by GET /api/v1/streams/<id> when the id is unknown. |
400 | | Zod validation failed on the request body, or the SSRF guard refused sourceUrl (loopback / RFC 1918 / link-local). |
Wire it up,
or skim the multi-endpoint view.
The multi-endpoint reference keeps streams alongside the agents feed on a single page; the quickstart walks the same flow end to end.