Skip to content

App API contract

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.

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.

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.

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.