App API contract
Version and capabilities
Section titled “Version and capabilities”GET /api/health/bootstrap returns the JSON API contract without authentication:
{ "api": { "version": 2, "features": [] }}api.version is a positive integer. It changes when a breaking change removes a
contract field, changes its type or meaning, or changes a required request
parameter. New optional fields and capabilities do not change the version.
Clients ignore unknown fields and feature names.
appVersion identifies the Aurral build. Nightly and preview build identifiers
are not API versions. The Subsonic protocol version is separate.
Feature names describe server capabilities added after version 2. They do not grant a permission or guarantee that an optional service is configured or available. The feature list is the same before and after sign-in.
Every version 2 server has the capabilities below, so features does not list
them. Version 1 servers listed each one under its feature name.
| Version 1 feature | Capability |
|---|---|
discover |
Discover recommendations and trending artists |
flows |
Flow creation and playlist status |
playlistCoverTemplates |
Artist and simple playlist covers through POST /api/playlists/artwork/:playlistId/generate with optional style: "artist" or style: "simple"; optional artworkRevision in playlist status changes when the saved cover changes; original covers restored through POST /api/playlists/artwork/:playlistId/restore |
activity |
Activity through /api/requests |
review |
Blocked download jobs and approval or denial |
trackDownloads |
Single-track requests through /api/library/downloads/track |
linkSearch |
Streaming-service links resolved through /api/search/link |
downloadCancel |
Cancelling one pending or downloading song through POST /api/playlists/jobs/:jobId/cancel, and searching again for cancelled songs that did not come from an album request |
shareImports |
Track, album, artist, and playlist sharing. POST /api/share-links/open resolves a share URL to a local destination without importing. POST /api/share-links/import/preview reviews a share URL, and POST /api/share-links/import queues details or permitted files, or with sync: true imports a playlist that syncs daily. Missing playlist entries imported without files have status saved. |
trending |
Song, album, artist, and genre charts through GET /api/discover/trending and GET /api/discover/trending/genres/:genreId |
flowAutoDownload |
Boolean autoDownload on flow objects, set through POST /api/playlists/flows and PUT /api/playlists/flows/:flowId. A flow with it off, or without a download source, lists new tracks with status saved and reuses tracks you already have. POST /api/playlists/flows/:flowId/download queues the flow’s saved tracks, and returns 409 with message when no download source is configured. |
pluginActions |
Menu actions from plugins. GET /api/plugins/actions lists the actions the signed-in user can run, each with pluginId, pluginName, id, label, and target (playlist, album, artist, or track). POST /api/plugins/:pluginId/actions/:actionId runs one with { "playlistId" }, { "albumId" }, { "artistId" }, or { "trackIds": [...] } to match its target, and returns message. A background action returns at once, and its result arrives on the plugins websocket channel as plugin_action_finished with ok and message. A failure returns error that starts with the plugin’s name. Show only targets your app knows. |
radio |
Radio stations from the Library. POST /api/library/radio takes any of trackIds, albumIds, and artists (each { id, mbid, name }) as seeds, plus optional exclude track ids and limit (1 to 100, default 25), and returns tracks ready for the queue, each with streamPath. Seeds outside the Library work through similar artists when a metadata source is available. Ask again with the tracks you already have in exclude to continue a station. |
playQueue |
The signed-in user’s saved play queue, shared with Subsonic getPlayQueue and savePlayQueue. GET /api/play-queue returns queue as null or with changed (milliseconds), changedBy, tracks in the shape radio returns, currentIndex, and positionMs. PUT /api/play-queue takes streamPaths from those tracks, the current index, positionMs, and a device name, and returns changed, which is null when the current track is not in the Library or a playlist. DELETE /api/play-queue with device and an optional changed clears the queue if that device saved it last or it has not changed since changed. The play-queue WebSocket channel sends play_queue_changed with changed and changedBy after each save. |
loudness |
A HEAD request on a track’s streamPath returns X-Aurral-Loudness, the file’s integrated loudness in LUFS. Aurral measures a file the first time it is asked and remembers it until the file changes. The header is absent when the file can’t be measured. |
albumPlaySorts |
Album pages from GET /api/library accept sort=played (the signed-in user’s recently played first), plays (most played first), released (newest release date first), and random. Without a signed-in user, played and plays return no albums. |
browsePlaylists |
Playlists to browse. GET /api/discover/playlists/made-for-you returns arrays discovery and mixes, built for the signed-in user. GET /api/discover/playlists returns arrays forYou and categories; each category has id, name, group (genre, mood, or decade), and playlists. Every playlist has provider (deezer, mix, or discovery), id, name, numeric trackCount, and nullable description, curator, and artworkUrl. GET /api/discover/playlists/:provider/:playlistId adds tracks, where a track in the Library has owned in the shape radio returns and other tracks play preview_url. POST to the same path plus /library saves it: a Deezer playlist syncs daily, a discovery playlist downloads its missing songs, and a mix saves its Library tracks. Mixes are also read-only Subsonic playlists with mix: ids. |
playlistTrackArtwork |
Every track from GET /api/playlists/jobs/:playlistId has nullable artworkUrl: the track’s custom artwork, or else its album cover. A track with custom artwork also has customArtworkUrl and nullable defaultArtworkUrl, the album cover. Album covers come from GET /api/artists/release-group/:mbid/cover/image, which redirects to the image and returns 404 when the album has none. |
Each capability added after version 2 gets its own name, and Aurral adds the name only when its routes are available. Clients check for that name before using those routes. An absent name means the server does not promise it.
The registry is backend/config/apiContract.ts. A capability change updates that
registry and this reference. The response checks in .tests/api/ pin the fields
below through HTTP requests.
Authentication and errors
Section titled “Authentication and errors”Password sign-in uses POST /api/auth/login with a JSON body containing
username and password. Subsequent requests use
Authorization: Bearer SESSION_TOKEN. The API overview covers
API keys and other authentication methods.
A JSON error contains a string error. Other error fields are optional.
401 means authentication failed or is missing. 403 means the credential
lacks the required permission. 404 means the requested resource is missing.
Service failures can return other error statuses. Clients inspect the status
before interpreting a success response.
Stable response fields
Section titled “Stable response fields”The routes and fields below form version 2 of the app contract. Responses may
contain additional fields. Arrays can be empty. Fields marked nullable can be
null.
| Route | Request | Success response |
|---|---|---|
POST /api/auth/login |
username, password |
String token, numeric expiresAt, and user |
GET /api/auth/me |
Authenticated session | user and nullable numeric expiresAt |
GET /api/health/bootstrap |
Public; optional credential | String status and appVersion, boolean authRequired and onboardingRequired, and api |
GET /api/discover |
Optional limit from 1 to 200 and offset |
Arrays recommendations, globalTop, basedOn, topTags, and topGenres; numeric recommendationCount; nullable string lastUpdated; boolean configured; string provider |
GET /api/discover/trending |
Authenticated session | Nullable string region, nullable numeric updatedAt, nullable objects songs and genreShare, nullable arrays albums and artists, and array genres |
GET /api/discover/trending/genres/:genreId |
Numeric genre ID from genres |
Numeric id and updatedAt, strings name and region, and array items of chart songs |
GET /api/search |
Required q; scope=artist or scope=album; optional limit, offset |
Strings scope and query, numeric count and offset, and array items |
GET /api/search/link |
Required url |
String kind and source; object artist; nullable objects album and track |
GET /api/artists/:mbid |
Artist MusicBrainz ID; optional mode=core |
Strings id and name, arrays tags, genres, release-groups, and appears-on-release-groups |
GET /api/artists/release-group/:mbid |
Release-group MusicBrainz ID | Strings id, title, and primary-type; arrays secondary-types, artist-credit, releases, and genres; nullable strings first-release-date and coverUrl; string overview |
GET /api/library |
Required kind=artists, albums, tracks, or genres, and pageSize from 1 to 100; optional page, source, availableOnly, filters, and compact=true, which leaves out items (the same list as the collection kind names) and genres unless kind=genres |
String kind; numeric page, pageSize, and total; boolean hasMore; arrays items, artists, albums, tracks, and genres |
GET /api/library/lookup/:mbid |
Artist MusicBrainz ID | Boolean exists and fromLibraryIndex, nullable object artist, array albums, and nullable string libraryArtistId |
POST /api/library/lookup/batch |
Array mbids |
Object keyed by requested IDs, with boolean values |
POST /api/library/albums/lookup/batch |
Array mbids |
Object keyed by found album IDs, with album lookup objects |
POST /api/library/albums/request |
albumMbid, albumName, artistMbid, artistName |
HTTP 201 with boolean success, createdArtist, createdAlbum, and queued; objects artist and album; string status |
POST /api/library/downloads/track |
artistName, trackName; optional track and album identifiers |
Boolean success and queued. An owned track returns HTTP 200 with alreadyOwned=true. An existing queued request returns HTTP 202 with string jobId and alreadyQueued=true. Other accepted requests return HTTP 202; jobId can be nullable for an already monitored track. |
POST /api/playlists/flows |
name, size, mix, scheduleDays, and scheduleTime, or a supported templateId |
Boolean success and object flow |
GET /api/playlists/status |
Requires accessPlaylists |
Arrays flows and staticPlaylists; objects stats, flowStats, worker, and hint |
GET /api/playlists/jobs |
Requires accessPlaylists; optional status=blocked for review |
Array of download job objects |
GET /api/requests |
Optional refresh=1 |
Array of activity objects |
POST /api/playlists/jobs/:jobId/approve |
Requires accessPlaylists; blocked job ID |
Boolean success and string path for the imported file |
POST /api/playlists/jobs/:jobId/deny |
Requires accessPlaylists; blocked job ID |
Boolean success |
user contains numeric id, strings username and role, and object
permissions. An authenticated bootstrap also includes user.
Discovery artist entries contain nullable string id and image, strings
name and type, and array tags. Search artist entries contain string id,
name, and type, nullable string image, array tags, and boolean
inLibrary. Search album entries contain strings id, title, artistName,
type, and status, and boolean inLibrary.
Trending charts are the same for every user, except libraryPlaylistId.
region is the country the charts follow. Each chart section is null until
Aurral has loaded it, and a section keeps its last loaded chart when a refresh
fails. songs contains strings playlistId and playlistName, nullable string
libraryPlaylistId, array items, and nullable object spotlight.
playlistId is the Deezer playlist ID, and libraryPlaylistId is set when the
user saved the chart as a playlist. spotlight contains numeric daysAtTop and
array ranks: the No. 1 song’s rank on each of the last 14 days, oldest first,
with null for days it was off the chart. It is null until Aurral has saved
two days of the chart.
Chart song entries contain strings key, trackName, and artistName, numeric
position, nullable strings albumName, artworkUrl, and preview_url, and
nullable numeric durationMs. Entries in songs.items also contain movement:
the number of places the song moved since the previous saved day, "new", or
null before Aurral has saved two days. Album entries contain strings key,
name, and artistName, numeric position, and nullable strings artworkUrl,
releaseDate, and genre. Artist entries contain strings key and name,
numeric position, nullable strings imageUrl and mbid, and nullable numeric
fans. genreShare contains numeric total and other and array genres of
objects with string name and numeric count. genres entries contain numeric
id, string name, and arrays covers and artists. A genre chart that Aurral
has not loaded returns 404.
A resolved link’s artist contains string name and nullable string mbid.
album contains string title and nullable string mbid; it is null for
artist links and for tracks whose album the service does not report. track
contains string title and nullable string mbid; it is null unless kind
is track. A null MusicBrainz ID means Aurral found no match, so search by
name instead. An unsupported link returns 400.
Artist release-group entries contain strings id, title, and primary-type,
array secondary-types, and nullable string first-release-date.
Library artist, album, and track entries use numeric id and string
identityKey. Artists have string name, albums have string title, and
tracks have strings title and artistName, nullable string mbid, and array
files. These IDs are different from MusicBrainz IDs and Subsonic IDs.
Album lookup objects contain boolean inLibrary and monitored, nullable
strings libraryAlbumId and libraryArtistId, string status, numeric
trackCount and trackFileCount, and array ownedTrackMbids. An absent key
means that the server did not find the album. ownedTrackMbids identifies
available tracks; it does not promise a complete album track list.
libraryAlbumId and libraryArtistId are null when the album is not in the
Library.
Flow objects contain strings id and name, numeric size and ownerUserId,
boolean enabled, and object mix. Existing legacy flows can have a nullable
ownerUserId. Download job objects contain strings id, status,
artistName, trackName, and playlistType, and nullable string streamFormat.
Activity objects contain string id, status, and title, and nullable
strings kind, artistName, and trackName. Activity combines several kinds
of events, so clients do not assume that every item describes a track.
Approval imports the held file and marks the job done. Denial removes the held
file and returns the job to the download queue. A missing or no-longer-blocked
job returns 404 with error.
Changes from version 1
Section titled “Changes from version 1”Version 2 removed these version 1 names. Apps that still read them need the current names.
| Version 1 | Version 2 |
|---|---|
GET /api/library/canonical |
GET /api/library |
/api/library/canonical-stream/:albumId/:trackId |
/api/library/stream/:albumId/:trackId |
PUT /api/library/canonical/artists/:id/mbid |
PUT /api/library/artists/:id/mbid |
readPath=canonical |
readPath=library |
/api/playlists/shared-playlists |
/api/playlists/static-playlists |
sharedPlaylists, sharedPlaylistStats, sharedStats |
staticPlaylists, staticPlaylistStats, staticStats |
accessFlow permission |
accessPlaylists |
canonical, canonicalInLibrary |
fromLibraryIndex |
canonicalId on Library artists, albums, and tracks |
id |
canonicalId on search results, artist lookups, and Aurral album responses |
libraryId |
albumCanonicalId on track search results, canonicalAlbumId on activity |
libraryAlbumId |
canonicalAlbumId, canonicalArtistId on album lookups |
libraryAlbumId, libraryArtistId |
canonicalTrackId in POST /api/library/downloads/track |
libraryTrackId |
managedBy on Library artists, albums, tracks, and album lookups |
Boolean managed |
managedBy and triggerSearch in POST /api/library/albums/request |
Removed |
/api/library/albums/aurral/:albumId |
/api/library/albums/:albumId |
/api/library/tracks/aurral/:trackId |
/api/library/tracks/:trackId |
aurral:<albumId> in GET /api/library/downloads/status |
The Library album ID |
monitorOption on artist requests and on artists and albums |
monitoring on requests. Removed from responses |
In version 1, libraryAlbumId and libraryArtistId on album lookups and
album search results held the IDs of the service that manages the album. In
version 2 they hold Library IDs on lookups. Version 2 has no providerAlbumId
or providerArtistId.