Skip to content
🚧 These docs are a work in progress and may contain inaccuracies. Content is being actively reviewed and validated.

REST API

Dubby provides a REST API at /v1/ for programmatic access to all server functionality. The API follows OpenAPI 3.1 conventions with auto-generated documentation.

  • OpenAPI spec: GET /v1/openapi.json
  • Swagger UI: GET /docs

The Swagger UI lets you explore endpoints, view request/response schemas, and make test requests directly from your browser.

The web client uses better-auth session cookies. Same-origin requests include the cookie automatically.

  1. Sign in to get a token:
Terminal window
curl -X POST http://localhost:3000/api/auth/sign-in/email \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "your-password"}'
  1. Use the token in subsequent requests:
Terminal window
curl http://localhost:3000/v1/movies \
-H "Authorization: Bearer <token>"

Sessions last 7 days and auto-extend every 24 hours on activity.

ConventionDetails
Content typeapplication/json for request and response bodies
IDsNanoid strings (21 characters)
PaginationCursor-based via cursor query parameter
Page sizelimit parameter (1-100, default 20)
Errors{ "error": "description" } with appropriate HTTP status
Validation422 with { "error": "Validation error", "details": [{ "path": "...", "message": "..." }] }
Max body1 MB (returns 413 if exceeded)
MethodEndpointDescription
GET/v1/librariesList libraries (filtered by user permissions)
POST/v1/librariesCreate a library
GET/v1/libraries/:idGet library details
PATCH/v1/libraries/:idUpdate a library
DELETE/v1/libraries/:idDelete a library (files on disk are not deleted)
POST/v1/libraries/:id/scanStart a library scan
GET/v1/libraries/:id/statsLibrary statistics
MethodEndpointDescription
GET/v1/moviesList movies with filters and sorting
GET/v1/movies/recently-addedRecently added movies
GET/v1/movies/:idMovie details
GET/v1/movies/:id/creditsCast and crew
PUT/v1/movies/:id/watchedMark as watched
DELETE/v1/movies/:id/watchedMark as unwatched
GET/v1/movies/:id/file-statsFile codec/resolution details
MethodEndpointDescription
POST/v1/playback/sessionsCreate a playback session
POST/v1/playback/sessions/:id/heartbeatKeep session alive, update position
POST/v1/playback/sessions/:id/seekSeek to a position
DELETE/v1/playback/sessions/:idEnd a session
GET/v1/playback/continue-watchingContinue watching list
GET/v1/playback/sessions/activeActive sessions
MethodEndpointDescription
POST/api/auth/sign-in/emailSign in
POST/api/auth/sign-outSign out
StatusMeaning
400Bad request
401Missing or invalid authentication
403Insufficient permissions
404Resource not found
409Conflict (e.g., scan already running)
413Request body too large
422Validation error
429Rate limit exceeded (check Retry-After header)
503Service unavailable
ScopeLimit
General API100 requests/minute
Speedtest3 requests/minute

Rate-limited responses include a Retry-After header indicating when you can retry.

Streaming uses separate routes outside the /v1/ prefix. See Stream Tokens for authentication details.

RouteDescription
GET /api/stream/:sessionId/master.m3u8HLS master playlist
GET /api/stream/:sessionId/:quality/playlist.m3u8Quality-specific playlist
GET /api/stream/:sessionId/:quality/:filenameHLS segment
GET /api/stream/:sessionId/fileDirect file (HTTP Range)
GET /api/stream/:sessionId/subtitles/:filenameWebVTT subtitle