StreamDek
Developers

API reference

Every endpoint this deployment serves, read straight from the running service. Start with the four things below, then find the resource you need.

Before you start

1. The base URL

Every path on this page is complete and already includes the version. Put your StreamDek API host in front of it:

https://api.streamdek.net/api/v1/watchlist

2. Authenticating

Every request that touches an account carries a bearer token:

Authorization: Bearer <token>

There are two kinds, and which you need depends on what you are building.

  • Acting for a viewer — an access token from the OAuth flow, obtained after they approve your application. This is what the Permission column below refers to: your token reaches an endpoint only if the viewer granted that permission. See Build on StreamDek.
  • Reading the catalogue only — a server-to-server key (sdk_…), from POST /api/v1/oauth/api-keys. It carries no account, so it reaches the media endpoints and nothing personal. Those endpoints take either kind of credential, but they do not answer anonymous requests.

3. Naming a title

Titles are identified by one string, everywhere — in paths, in webhook payloads, in remote commands. It carries the namespace it was resolved in, so you can address a title by whichever id you already hold:

movie:tmdb:550          a film
tv:tmdb:1399            a series
tv:tmdb:1399:s2         one of its seasons
tv:tmdb:1399:s2e5       one episode
movie:imdb:tt0137523    the same film, by IMDb id

GET /api/v1/media/{ref} resolves any of them and answers with the canonical spelling — that is the one to store.

4. When something goes wrong

Every failure has the same shape, and the code is what you should branch on:

{ "error": { "code": "INSUFFICIENT_SCOPE", "message": "…", "requestId": "req-9" } }

Quote the requestId if you need to ask us about a specific response.

A complete example

Reading a viewer’s watchlist, then adding a film to it:

curl -H "Authorization: Bearer $TOKEN"   https://api.streamdek.net/api/v1/watchlist

curl -X PUT -H "Authorization: Bearer $TOKEN"   https://api.streamdek.net/api/v1/watchlist/movie:tmdb:550

The first needs watchlist:read, the second watchlist:write. Lists are paginated: the response carries page.nextCursor, which you pass back as ?cursor= until it is null.

The machine-readable description

openapi.json — the full OpenAPI 3.1 document for this deployment, generated from the live route table. Point a client generator at it rather than transcribing anything from this page.

Endpoints you can use

Grouped by what they are about. Permission is what a viewer has to grant you; a dash means none is needed — those are public, or they are how your own application is set up.

Media and search

Finding a title and reading its details. No account is involved and no viewer’s permission is needed — but a credential is: a server-to-server key is enough.

EndpointWhat it doesPermissionStage
GET /api/v1/media/
  • q query · string, up to 191 characters · required
  • type query · movie | tv
  • limit query · integer, 1-100
Search the catalogue.—Beta
GET /api/v1/media/{ref}
  • ref in path · string, up to 191 characters · required
One title by canonical reference: movie, series, season or episode.—Beta

Watchlist

The account watchlist. Titles are named by reference; see “Naming a title” above.

EndpointWhat it doesPermissionStage
GET /api/v1/watchlist/
  • limit query · integer, 1-100
  • cursor query · string, up to 512 characters
The account watchlist, paginated.watchlist:readBeta
DELETE /api/v1/watchlist/{ref}
  • ref in path · string, up to 191 characters · required
Removes a title from the watchlist. Idempotent.watchlist:writeBeta
PUT /api/v1/watchlist/{ref}
  • ref in path · string, up to 191 characters · required
Adds a title to the watchlist. Idempotent.watchlist:writeBeta

Playback progress

Playback positions, and the Continue Watching shortlist built from them.

EndpointWhat it doesPermissionStage
GET /api/v1/continue-watching/
  • limit query · integer, 1-100
The shortlist, removals applied. Not paginated by design.progress:readBeta
DELETE /api/v1/continue-watching/{ref}
  • ref in path · string, up to 191 characters · required
Removes a title, one of its seasons, or one episode -- whichever the ref names.progress:writeBeta
GET /api/v1/progress/
  • limit query · integer, 1-100
  • cursor query · string, up to 512 characters
  • status query · string, up to 32 characters
Every recorded position, paginated. The record, not the shortlist.progress:readBeta
GET /api/v1/progress/{ref}
  • ref in path · string, up to 191 characters · required
One title position. 404 when none is recorded.progress:readBeta
PUT /api/v1/progress/{ref}
  • ref in path · string, up to 191 characters · required
Takes a JSON body.
Records a position. Mirrors to connected providers on the same terms a first-party write does.progress:writeBeta

Watched history

What the account has finished watching.

EndpointWhat it doesPermissionStage
GET /api/v1/history/
  • limit query · integer, 1-100
  • cursor query · string, up to 512 characters
What the account has finished, paginated.history:readBeta
DELETE /api/v1/history/{ref}
  • ref in path · string, up to 191 characters · required
Marks a title unwatched.history:writeBeta
PUT /api/v1/history/{ref}
  • ref in path · string, up to 191 characters · required
Takes a JSON body.
Marks a title watched.history:writeBeta

Library

Counts across the account library, for a dashboard.

EndpointWhat it doesPermissionStage
GET /api/v1/library/Counts across the account library.library:readBeta

Account, profiles and devices

The signed-in account: its display name, its viewing profiles, and the devices signed in to it.

EndpointWhat it doesPermissionStage
GET /api/v1/devices/The devices signed in to this account.devices:readBeta
GET /api/v1/profile/The account display name and its viewing profiles. No email, no preferences.profile:readBeta

Webhooks

Being told when something happens, instead of polling for it.

EndpointWhat it doesPermissionStage
GET /api/v1/webhooks/This application subscriptions on this account.—Beta
POST /api/v1/webhooks/
Takes a JSON body.
Subscribes to events. Returns the signing secret, once.—Beta
DELETE /api/v1/webhooks/{id}
  • id in path · string, up to 64 characters · required
Deletes a subscription and cancels its pending deliveries.—Beta
PATCH /api/v1/webhooks/{id}
  • id in path · string, up to 64 characters · required
Takes a JSON body.
Changes the URL, the event list, or the paused state.—Beta
GET /api/v1/webhooks/{id}/deliveries
  • limit query · integer, 1-100
  • cursor query · string, up to 512 characters
  • id in path · string, up to 64 characters · required
The delivery log: what was sent, what came back, and what is still due.—Beta
POST /api/v1/webhooks/{id}/rotate-secret
  • id in path · string, up to 64 characters · required
Replaces the signing secret. The old one stops verifying immediately.—Beta
GET /api/v1/webhooks/eventsEvery event type, and the scope a subscription needs to receive it.—Beta

Applications and tokens

Registering your application, and exchanging its credentials for tokens. Called with your own client credentials, not a viewer’s token.

EndpointWhat it doesPermissionStage
GET /api/v1/oauth/api-keysThe keys this account holds.—Beta
POST /api/v1/oauth/api-keys
Takes a JSON body.
A server-to-server key for public data. Carries no account and reaches nothing scoped to one.—Beta
DELETE /api/v1/oauth/api-keys/{id}
  • id in path · string, up to 64 characters · required
Revokes a key.—Beta
GET /api/v1/oauth/appsThe applications this account has registered.—Beta
POST /api/v1/oauth/apps
Takes a JSON body.
Registers an application. Returns both environments credentials, once.—Beta
POST /api/v1/oauth/apps/{id}/rotate-secret
  • id in path · string, up to 64 characters · required
Takes a JSON body.
Replaces one environment client secret. The old one stops working immediately.—Beta
GET /api/v1/oauth/apps/{id}/usage
  • from query · string, up to 10 characters
  • to query · string, up to 10 characters
  • id in path · string, up to 64 characters · required
One application own usage, its rate-limit ceiling, and how many viewers connected it.—Beta
GET /api/v1/oauth/authorize
  • client_id query · string, up to 128 characters · required
  • redirect_uri query · string, up to 512 characters · required
  • scope query · string, up to 256 characters · required
  • code_challenge query · string, up to 128 characters · required
  • code_challenge_method query · S256 · required
  • state query · string, up to 256 characters
Describes an authorization request so a consent screen can be rendered. Grants nothing.—Beta
POST /api/v1/oauth/authorize
Takes a JSON body.
Consent. Returns the redirect the client should follow, carrying a one-use code.—Beta
POST /api/v1/oauth/revoke
Takes a JSON body.
RFC 7009. Ends a grant and every token under it.—Beta
GET /api/v1/oauth/scopesEvery scope, in the words a viewer sees, and the routes each one reaches.—Beta
POST /api/v1/oauth/token
Takes a JSON body.
Exchanges an authorization code, or rotates a refresh token.—Beta

Documentation

This documentation, and the machine-readable description behind it.

EndpointWhat it doesPermissionStage
GET /api/v1/docs/Everything an integrator needs before writing code, in one call.—Beta
GET /api/v1/docs/lifecycleThe stage of every endpoint: stable, beta, experimental or deprecated.—Beta
GET /api/v1/docs/openapi.jsonThe OpenAPI description, generated from the live route table.—Beta