Skip to content

Latest commit

 

History

History
301 lines (234 loc) · 12.4 KB

File metadata and controls

301 lines (234 loc) · 12.4 KB
title API reference
description Every route the server serves, generated from the router itself.

A self-hosted music library. Everything the first-party front end does, it does through this API and nothing else — there is no privileged route, which is the only way that guarantee means anything.

Five rules shape it: cursor pagination and never OFFSET, revision-based deltas, collection ETags, one round trip per page with presence and renditions embedded, and server-sent events rather than polling.

A Subsonic-compatible API is also served at /rest, which this document does not describe: it is somebody else's specification and is documented by them.

Base URL: /api/v1

Authentication is a bearer token, or ?token= for the places that cannot set a header — <audio src> being the reason that exists. A server with no accounts answers everything, so a fresh install is usable before anyone has created a login.

accounts

Path What it does
GET /users Every account. Admin only; no secret ever leaves here.
POST /users Creates an account. Roles: admin, user, guest — a guest plays and nothing else.
DELETE /users/{id} Removes an account and its tokens. Not the last admin.
PATCH /users/{id} Changes a role or a password. Refuses to demote the last admin.
GET /users/{id}/sources Which sources this account may see. all when it has not been narrowed.
PUT /users/{id}/sources Narrows an account to some sources. An empty list restores all of them.

POST /users
Body: { username, password, role? }

PATCH /users/{id}
Body: { role?, password? }

PUT /users/{id}/sources
Body: { sourceIds: [] }

auth

Path What it does
POST /auth/login Exchanges a password for a token.
GET /auth/me The signed-in user, with the capabilities it has and the sources it may see.
POST /auth/setup Claims a fresh install. Refused once any account exists.
GET /auth/state Whether this install has been claimed yet.
GET /auth/tokens Tokens belonging to the signed-in user. Secrets are never returned.
POST /auth/tokens Issues a token. The secret is shown once and only its hash is kept.
DELETE /auth/tokens/{id} Revokes a token.

POST /auth/login
Body: { username, password }

POST /auth/setup
Body: { username, password }

backup

Path What it does
GET /backup Everything a rescan cannot rebuild. Secrets excluded unless asked.
POST /restore Applies a backup. Adds; never replaces.

GET /backup
Query: secrets

devices

Path What it does
GET /devices Connected devices.
POST /devices Satellite registration. Idempotent on the device id.
PATCH /devices/{id} Renames it or changes what it syncs.
POST /devices/{id}/backup Backs the device up.
POST /devices/{id}/eject Disconnects without forgetting anything.
POST /devices/{id}/import Pulls tracks the device has and the library does not.
GET /devices/{id}/stats Counts and orphans on the device.
POST /devices/{id}/sync Syncs. With dryRun returns the plan and writes nothing.
GET /devices/{id}/tracks What the device actually holds, library or not.
PUT /devices/{id}/tracks A satellite reporting the device contents.
DELETE /devices/{id}/wanted Un-picks them.
POST /devices/{id}/wanted Hand-picks tracks for a device. They join the sync rules.

jobs

Path What it does
GET /events Server-sent events. One stream; clients never poll.
GET /jobs Background work.
DELETE /jobs/{id} Cancels it.
GET /jobs/{id} One job.
PATCH /jobs/{id} Pauses or resumes it.
GET /jobs/{id}/items What it did item by item, with counts over the whole job.

library

Path What it does
GET /artwork/{id} Cover art, extracted on demand and ETagged on the file.
GET /facets Distinct genres, artists, albums and formats, with counts.
GET /stream/{id} The audio, honouring Range. Converts on the fly when the library holds nothing the client accepts — that response carries no Range and an X-Jukebox-Transcoded header.
GET /tracks One page of tracks, with device presence and renditions.
PATCH /tracks Edits one or many. Tag writing to disk becomes a job.
GET /tracks/{id} One track.
GET /tracks/{id}/memberships Every playlist and device holding this track. Smart playlists are asked, not read.
POST /tracks/{id}/play Records a listen. Half the length or four minutes, never under thirty seconds.
GET /tracks/count How many tracks a query matches.
GET /tracks/delta What changed since a revision. The main network win.
GET /tracks/missing Tracks whose file the scanner can no longer find.
POST /tracks/tags Adds and removes tags on a set of tracks. Add/remove rather than replace, so tagging a selection cannot silently clear what the tracks did not have in common.

GET /stream/{id}
Query: rendition, format, accept, seek

GET /tracks
Query: sort, cursor, limit, q, genre, artist, album, format, tag, kind, sourceId, rating, ratingMin, lossless, onDevice, notOnDevice, match

PATCH /tracks
Body: { ids, patch, writeToFiles? }

POST /tracks/{id}/play
Body: { played, startedAt? }

GET /tracks/delta
Query: since, limit

POST /tracks/tags
Body: { ids, add?, remove? }

outputs

Path What it does
GET /outputs Renderers on the network — UPnP by SSDP, AirPlay by multicast DNS — plus satellites that registered themselves.
DELETE /outputs/{id} Forgets a registered output. Discovered ones come back on their own.
POST /outputs/{id}/pause Pauses it.
POST /outputs/{id}/play Points a renderer at a track and starts it.
POST /outputs/{id}/stop Stops it.
POST /outputs/{id}/volume Sets its volume, 0 to 100. AirPlay answers 501: its volume lives in RTSP, not this protocol.
POST /outputs/register A satellite announcing it can play. Re-registering is also its heartbeat.

GET /outputs
Query: refresh

POST /outputs/register
Body: { id, name, url, formats? }

player

Path What it does
GET /player The shared queue: what is playing, where, and who last changed it.
PATCH /player Changes the output, repeat or shuffle.
POST /player/goto Jumps to a track already in the queue.
POST /player/next Next track. Stops at the end unless repeat is on.
POST /player/pause Pauses.
POST /player/play Resumes.
POST /player/previous Previous track, or restarts this one.
DELETE /player/queue Empties it.
POST /player/queue Adds to it. next: true puts them after the current track.
PUT /player/queue Replaces the queue and starts it.
POST /player/report A renderer saying where it actually is. It may not reorder anything.
POST /player/seek Moves the playhead.

PATCH /player
Body: { target?, repeat?, shuffle? }

POST /player/goto
Body: { trackId }

POST /player/queue
Body: { trackIds, next? }

PUT /player/queue
Body: { trackIds, startAt? }

POST /player/report
Body: { position, playing? }

POST /player/seek
Body: { position }

playlists

Path What it does
GET /playlists Every playlist, manual and smart.
POST /playlists Creates one.
DELETE /playlists/{id} Deletes it.
GET /playlists/{id} One playlist.
PATCH /playlists/{id} Renames it.
PUT /playlists/{id}/order Moves a batch, preserving its relative order.
DELETE /playlists/{id}/tracks Removes tracks.
GET /playlists/{id}/tracks Its contents. A smart playlist runs its query.
POST /playlists/{id}/tracks Adds tracks, deduplicated.

POST /playlists
Body: { name, smart?, rules?, trackIds? }

plugins

Path What it does
GET /plugins Installed plugins, and what each can be asked to do right now.
GET /plugins/{id} One plugin.
PATCH /plugins/{id} Enables, disables or configures it.
POST /plugins/{id}/command Runs something a plugin contributed.
POST /plugins/scan Re-reads the plugin folder. Failures are listed with their reason.
GET /store Browses a plugin index. There is no default store, on purpose.
DELETE /store/{id} Uninstalls it.
POST /store/install Downloads, verifies and installs one.

POST /plugins/{id}/command
Body: { command, trackIds? }

GET /store
Query: index

POST /store/install
Body: { index, id }

podcasts

Path What it does
GET /podcasts Subscriptions.
POST /podcasts Subscribes and fetches straight away.
DELETE /podcasts/{id} Unsubscribes.
GET /podcasts/{id} One subscription.
PATCH /podcasts/{id} Changes its refresh, retention or destination.
GET /podcasts/{id}/episodes Episodes, newest first.
POST /podcasts/{id}/refresh Refreshes now. Conditional: unchanged feeds cost no body.

POST /podcasts
Body: { feedUrl, cron?, keepLast?, autoDownload? }

radios

Path What it does
GET /radios Stations.
POST /radios Adds one, discovering its name and logo unless told not to.
DELETE /radios/{id} Removes it.
GET /radios/{id} One station.
PATCH /radios/{id} Edits it.
POST /radios/{id}/discover Re-runs discovery, filling blanks only.

schedules

Path What it does
GET /schedules Recurring work.
POST /schedules Adds one. The cron expression is validated now, not at fire time.
DELETE /schedules/{id} Removes it.
PATCH /schedules/{id} Edits it.
POST /schedules/{id}/run Runs it now, without moving its next occurrence.

server

Path What it does
GET /health Liveness. The one route that never needs credentials.
GET /openapi.json This document.
GET /stats Library totals, computed in SQL over the whole library rather than a page.

sources

Path What it does
GET /duplicates Rows that look like one song. Proposes; never merges.
POST /duplicates/merge Folds tracks into one, moving their files across as renditions.
POST /organize What moving files into a pattern would do. Dry unless apply.
POST /organize/{jobId}/undo Puts a reorganisation back, newest move first.
GET /organize/log Every file a reorganisation moved.
GET /sources Where the music lives.
POST /sources Adds a source. rclone sources carry config: { url, fs }.
POST /sources/{id}/scan Indexes a source. full re-reads every file; prune confirms deleting every track when the source turns up empty, which an unmounted share also does.
POST /sources/{id}/test Does this source answer? Better asked before a scan than read from its error afterwards.
POST /transcode Converts a selection. replace: false keeps both as renditions.
GET /transcode/capabilities Whether ffmpeg is present, and what it can write.

POST /duplicates/merge
Body: { keeperId, ids }

POST /organize
Body: { sourceId, pattern, apply? }

POST /sources/{id}/scan
Query: full, prune

POST /transcode
Body: { ids, format, quality?, replace }

Not described here

A Subsonic-compatible API is served at /rest. It is somebody else's specification and they document it; every client written for it in the last twenty years works against this server unchanged.