REST API Reference
The SnapDog REST API is hosted on port 5555 by default (configurable via [http].port in snapdog.toml). JSON endpoints use the application/json Content-Type; cover-art endpoints return raw image bytes.
1. Authentication & Security
Section titled “1. Authentication & Security”If token security is activated in snapdog.toml (via [http].api_keys), all clients must include the bearer token in their request headers:
Authorization: Bearer <your-configured-api-key>Accept: application/jsonAuthentication Errors
Section titled “Authentication Errors”Requests with missing, malformed, or invalid tokens return a 401 Unauthorized status with a plain-text body:
Invalid or missing API key2. Interactive Scalar Console
Section titled “2. Interactive Scalar Console”If SnapDog is compiled with the api-docs feature flag and api_docs = true is set in the [http] section of your configuration, you can access the built-in documentation server directly:
- Scalar Interactive Console:
http://<device-ip>:5555/docs - Runtime OpenAPI: The OpenAPI document is embedded in the Scalar page. The project also generates a standalone JSON file for docs publishing via
cargo run --package xtask -- gen-api-spec openapi.json.
Console Capabilities
Section titled “Console Capabilities”The embedded Scalar interface provides a modern developer playground with several key features:
- Drift-Free Specifications: The OpenAPI registry is generated at build/compile time using Rust’s
utoipacrate. This guarantees the console endpoints and payload schemas are always 100% in sync with the active server version. - Sandbox Testing: You can test requests and execute endpoints directly against live hardware from your browser.
- Authentication Helper: If API key security is enabled, click the Authorize lock button in the Scalar header and input your token. Scalar automatically injects the matching
Authorization: Bearer <key>header into sandbox requests. - Multi-Language Code Generator: Select any endpoint to generate copy-pasteable client integration snippets in
cURL,JavaScript,Python,Rust,Go,PHP, and more. - Fuzzy Search: Press
/within the console to trigger fuzzy search indexing across all endpoints, tags, and request schemas.
3. System Endpoints
Section titled “3. System Endpoints”Get System Summary Statistics
Section titled “Get System Summary Statistics”Returns count statistics for configured zones, clients, and radio streams.
- Method:
GET - Endpoint:
/api/v1/system/status - Response
200 OK:{"version": "1.0.0","zones": 2,"clients": 4,"radios": 12}
Get Application and Platform Version
Section titled “Get Application and Platform Version”Returns detailed package and compilation versions along with the host name.
- Method:
GET - Endpoint:
/api/v1/system/version - Response
200 OK:{"version": "1.0.0","rust_version": "1.78.0","name": "SnapDog Controller"}
Health Probes
Section titled “Health Probes”Health endpoints are mounted at the server root, outside the /api/v1 prefix.
- Method:
GET - Endpoints:
/health— Returns{ "status": "ok", "zones": <count>, "clients": <count> }./health/ready— Returns plain textready./health/live— Returns plain textlive.
List Network Listeners
Section titled “List Network Listeners”One row per listener of the server: service, protocol, address, port, what creates the socket, and how far the service honours a bind setting. Use it to derive firewall rules. A port of 0 means a random port at every start.
- Method:
GET - Endpoint:
/api/v1/system/listeners - Response
200 OK:The response is an array of such objects.{"service": "HTTP API","protocol": "tcp","address": "192.168.1.10","port": 5555,"backend": "axum","bind_support": "full","note": "[http].bind, one listener per address","via": "eth0"}bind_supportisfull,partialornone.viais present only when the address came from an interface name orloopbackin abindsetting.
Container Updater
Section titled “Container Updater”These endpoints talk to the updater sidecar of the Docker deployment. They need SNAPDOG_UPDATER_URL and UPDATER_TOKEN (see deploy/docker-compose.yml). Without them, and outside the Docker deployment, every one of them answers 503 Service Unavailable. A sidecar that does not answer, or refuses, makes them answer 502 Bad Gateway.
GET /api/v1/system/updatesreads the state of the updater.POST /api/v1/system/updates/checkasks the sidecar to look for a newer release now. It answers with the state once the check has started. A check or update that already runs makes the sidecar refuse, which shows up as502.POST /api/v1/system/updates/applyapplies the available update now. The sidecar pulls the new image, verifies it and restarts the server, so the connection drops while this runs. It does nothing if no update is available.POST /api/v1/system/updates/configchanges the update mode and the maintenance window. The body is rejected with422when it is malformed or has an unknown field.
All four answer 200 OK with the state of the updater:
{ "state": "idle", "updateAvailable": true, "currentVersion": "0.30.0", "availableVersion": "0.31.0", "updateMode": "automatic", "maintenanceTime": "02:00", "timezone": "Europe/Berlin", "lastError": null, "progress": null}The request body of /api/v1/system/updates/config:
{ "mode": "automatic", "maintenanceTime": "02:00", "timezone": "Europe/Berlin"}mode is manual (checks and applies only when asked) or automatic (applies new releases at maintenanceTime, read in timezone). state is for example idle, checking or updating, and progress is an object with a phase while an update runs.
4. Zone Management & Playback
Section titled “4. Zone Management & Playback”Zones represent rooms or audio output groups. You can query their states and send actions like play, pause, volume scales, seek operations, or presence adjustments.
List Zones
Section titled “List Zones”- Method:
GET - Endpoint:
/api/v1/zones - Response
200 OK:[{"index": 1,"name": "Living Room","icon": "sofa","volume": 75,"muted": false,"playback": "playing","source": "subsonic_playlist","shuffle": false,"repeat": "off","presence": false,"presence_enabled": true,"presence_timer_active": false}]
source values are the Rust SourceType strings: idle, radio, subsonic_playlist, subsonic_track, url, airplay, or spotify.
Get Zone Count
Section titled “Get Zone Count”- Method:
GET - Endpoint:
/api/v1/zones/count - Response
200 OK:2
Get Single Zone Status
Section titled “Get Single Zone Status”- Method:
GET - Endpoint:
/api/v1/zones/{zone_index} - Response
200 OK: (Returns the single zone object depicted in the list output) - Response
404 Not Found:{"error": "not_found","message": "Zone index 99 does not exist"}
Get or Set Zone Volume
Section titled “Get or Set Zone Volume”Volume can be adjusted absolutely (0 to 100) or relative to the current level ("+5", "-10").
- Method:
GET|PUT - Endpoint:
/api/v1/zones/{zone_index}/volume - Request Body (PUT):
or{"volume": 80}{"volume": "+10"}
- Response
200 OK:80(new resolved volume)
Get or Set Zone Mute State
Section titled “Get or Set Zone Mute State”- Method:
GET|PUT - Endpoint:
/api/v1/zones/{zone_index}/mute - Request Body (PUT):
trueorfalse - Response
200 OK:true
Toggle Zone Mute State
Section titled “Toggle Zone Mute State”- Method:
POST - Endpoint:
/api/v1/zones/{zone_index}/mute/toggle - Response
200 OK:false(returns the new resolved mute status)
Play / Pause / Stop Commands
Section titled “Play / Pause / Stop Commands”- Method:
POST - Endpoints:
/api/v1/zones/{zone_index}/play/api/v1/zones/{zone_index}/pause/api/v1/zones/{zone_index}/stop
- Response
200 OK: Returns nothing on success, or an error if playback fails.
Track Navigation
Section titled “Track Navigation”Skip tracks inside the current active playlist.
- Method:
POST - Endpoints:
/api/v1/zones/{zone_index}/next/api/v1/zones/{zone_index}/previous
- Response
200 OK: Success payload or standard HTTP status.
Playlist Selection and Navigation
Section titled “Playlist Selection and Navigation”Read or select the unified playlist assigned to a zone, or move between the available radio/Subsonic playlists.
- Methods and endpoints:
GET /api/v1/zones/{zone_index}/playlist— returns the active zero-based playlist index.PUT /api/v1/zones/{zone_index}/playlist— accepts a JSON integer playlist index.GET /api/v1/zones/{zone_index}/playlist/by-id— returns the activeplaylist_idas a JSON string, or""if no playlist is active.PUT /api/v1/zones/{zone_index}/playlist/by-id— accepts a bare JSON string with aplaylist_id, for example"subsonic:42". If the zone is playing, playback switches to that playlist, otherwise it is loaded.POST /api/v1/zones/{zone_index}/next/playlist— selects the next playlist.POST /api/v1/zones/{zone_index}/previous/playlist— selects the previous playlist.
- Response
404 Not Found: The requested zone does not exist. On theby-idendpoints, an unknownplaylist_idalso returns404.
Retrieve Current Track Details
Section titled “Retrieve Current Track Details”- Method:
GET - Endpoint:
/api/v1/zones/{zone_index}/track - Response
200 OK:3(index of active track in the playlist)
Retrieve Full Track Metadata
Section titled “Retrieve Full Track Metadata”Returns all tags of the currently playing stream.
- Method:
GET - Endpoint:
/api/v1/zones/{zone_index}/track/metadata - Response
200 OK:{"title": "Acoustic Song","artist": "The Band","album": "Unplugged","album_artist": "The Band","genre": "Rock","year": 2024,"track_number": 2,"disc_number": 1,"duration_ms": 240000,"position_ms": 12400,"seekable": true,"bitrate_kbps": 320,"content_type": "audio/flac","sample_rate": 48000,"source": "subsonic_playlist","cover_url": "/api/v1/zones/1/cover","playlist_index": 1,"playlist_id": "subsonic:42","playlist_name": "My Acoustic Playlist","playlist_total": 5,"playlist_track_index": 1,"playlist_track_count": 12,"can_playlist_next": true,"can_playlist_prev": false,"can_next": true,"can_prev": false}
playlist_id is the stable reference of the active playlist (null if none is active). playlist_index is its current position in the unified list and can change, see Playlist Selection and Navigation.
cover_url is usually an API path such as /api/v1/zones/1/cover; receiver integrations may also provide an absolute HTTP(S) URL.
Retrieve Cover Art Image
Section titled “Retrieve Cover Art Image”Fetches the cover image binary. If no cover is active, returns the default SnapDog placeholder PNG.
- Method:
GET - Endpoint:
/api/v1/zones/{zone_index}/cover - Response
200 OK: Raw image binary stream.- Headers include:
Content-Type: image/jpeg(or png),Cache-Control: public, max-age=86400, immutable, and matchingETag.
- Headers include:
Specific Metadata Tag Endpoints
Section titled “Specific Metadata Tag Endpoints”Quick shortcuts to pull separate tags.
- Method:
GET - Endpoints:
/api/v1/zones/{zone_index}/track/title(returns JSON String)/api/v1/zones/{zone_index}/track/artist(returns JSON String)/api/v1/zones/{zone_index}/track/album(returns JSON String)/api/v1/zones/{zone_index}/track/duration(returns JSON Integer in ms)/api/v1/zones/{zone_index}/track/playing(returns JSON Boolean)
Seek Position
Section titled “Seek Position”- Method:
GET|PUT - Endpoint:
/api/v1/zones/{zone_index}/track/position - Request Body (PUT): Provide exactly one of
position_ms(absolute position) oroffset_ms(relative position).or{"position_ms": 45000}{"offset_ms": -5000} - Response
200 OK:40000(returns absolute position in ms)
Seek Progress
Section titled “Seek Progress”Allows querying or seeking via a normalized percentage float (0.0 to 1.0).
- Method:
GET|PUT - Endpoint:
/api/v1/zones/{zone_index}/track/progress - Request Body (PUT):
0.5(seeks to the middle of the track) - Response
200 OK:0.5
Direct Playback Trigger Endpoints
Section titled “Direct Playback Trigger Endpoints”Instructs a zone to immediately play a specific track, URL stream, or Subsonic playlist.
- Method:
POST - Endpoints & Requests:
/api/v1/zones/{zone_index}/play/track— Request Body: track index (e.g.2)./api/v1/zones/{zone_index}/play/url— Request Body: absolute URL string./api/v1/zones/{zone_index}/play/playlist— Request Body (the playlist index):{"index": 1,"track": 0}idis still accepted instead ofindex. Deprecated. Useindex. Removed with SnapDog 1.0, which breaks compatibility of/api/v1for clients that still read it. Sending both with different values returns400 Bad Request. New clients must sendindexonly./api/v1/zones/{zone_index}/play/playlist/by-id— Request Body (theplaylist_id;trackdefaults to0):An unknown{"playlist_id": "subsonic:42","track": 0}playlist_idreturns404 Not Found./api/v1/zones/{zone_index}/play/playlist/{playlist_index}/track— Request Body: track index. The current handler accepts the playlist path segment for compatibility and selects the track within the zone’s active playlist./api/v1/zones/{zone_index}/play/subsonic/{track_id}— Starts a Subsonic server file stream.
Shuffle & Repeat
Section titled “Shuffle & Repeat”- Method:
GET|PUT - Endpoints:
/api/v1/zones/{zone_index}/shuffle— Query/set boolean./api/v1/zones/{zone_index}/repeat— Query/set mode:"off","track","playlist".
- Method:
POST - Endpoints:
/api/v1/zones/{zone_index}/shuffle/toggle/api/v1/zones/{zone_index}/repeat/toggle
Presence Detection Automation
Section titled “Presence Detection Automation”Configures auto-off triggers when motion sensors report room occupancy states.
- Method:
GET|PUT - Endpoints:
/api/v1/zones/{zone_index}/presence— Occupation state (JSON bool)./api/v1/zones/{zone_index}/presence/enable— Enable/disable presence automation (JSON bool)./api/v1/zones/{zone_index}/presence/timeout— Duration in seconds of no motion before turning off the zone (JSON u16)./api/v1/zones/{zone_index}/presence/timer— Returns active countdown status (JSON bool).
Zone Property Shortcuts
Section titled “Zone Property Shortcuts”Helper endpoints to fetch specific zone configuration properties individually.
- Method:
GET - Endpoints:
/api/v1/zones/{zone_index}/name— Returns the zone display name as a JSON String./api/v1/zones/{zone_index}/icon— Returns the zone icon tag as a JSON String./api/v1/zones/{zone_index}/playback— Returns the active playback status ("playing","paused", or"stopped") as a JSON String./api/v1/zones/{zone_index}/playlist/name— Returns the active playlist name as a JSON String./api/v1/zones/{zone_index}/playlist/info— Returns the active playlist summary (index,playlist_id,name,total,track_count,track_index)./api/v1/zones/{zone_index}/playlist/count— Returns the number of tracks in the active playlist./api/v1/zones/{zone_index}/clients— Returns an array of client speaker indices currently assigned to this zone.
5. DSP & Zone Equalizer
Section titled “5. DSP & Zone Equalizer”Equalizers configured at the zone level are applied to the resampled master stream on the server.
Get Zone EQ configuration
Section titled “Get Zone EQ configuration”- Method:
GET - Endpoint:
/api/v1/zones/{zone_index}/eq - Response
200 OK:{"enabled": true,"preset": "custom","bands": [{ "freq": 125, "q": 1.0, "gain": 4.5, "type": "peaking" }]}
Modify EQ Bands
Section titled “Modify EQ Bands”Allows patching specific filters.
- Method:
PUT - Endpoint:
/api/v1/zones/{zone_index}/eq - Request Body:
{"enabled": true,"bands": [{ "freq": 125, "q": 1.0, "gain": 2.0, "type": "peaking" }]}
- Response
200 OK: Returns full modifiedEqConfigobject.
Load EQ Preset
Section titled “Load EQ Preset”Quickly overwrite current EQ settings with a standard curve.
- Method:
POST - Endpoint:
/api/v1/zones/{zone_index}/eq/preset - Request Body:
"bass_boost"(supported:flat,bass_boost,loudness,vocals,treble_boost) - Response
200 OK: Returns loadedEqConfig.
List EQ Presets
Section titled “List EQ Presets”Returns every preset name that the eq/preset calls accept, with the bands each one sets.
- Method:
GET - Endpoint:
/api/v1/eq/presets - Response
200 OK:The response is an array of such objects in a fixed order, one per preset name. A preset other than{"name": "flat","bands": []}flatlists the bands it sets, each one like the bands of the zone EQ above.
Modify Single Zone EQ Band
Section titled “Modify Single Zone EQ Band”- Method:
PUT - Endpoint:
/api/v1/zones/{zone_index}/eq/{band_index} - Request Body:
{ "freq": 1000, "q": 1.0, "gain": -1.5, "type": "peaking" }
6. Connected Client Speakers
Section titled “6. Connected Client Speakers”Client speakers represent physical hardware players.
List Connected Speakers
Section titled “List Connected Speakers”- Method:
GET - Endpoint:
/api/v1/clients - Response
200 OK:[{"index": 1,"name": "Kitchen Speaker","mac": "02:42:ac:11:00:10","zone_index": 1,"icon": "cook","volume": 85,"max_volume": 100,"muted": false,"connected": true,"is_snapdog": true}]
Get or Set Client Volume
Section titled “Get or Set Client Volume”- Method:
GET|PUT - Endpoint:
/api/v1/clients/{client_index}/volume - Request Body (PUT): absolute integer or relative string increment (
80or"+5").
Mute Controls
Section titled “Mute Controls”- Method:
GET|PUT|POST - Endpoints:
GET/PUT/api/v1/clients/{client_index}/mutePOST/api/v1/clients/{client_index}/mute/toggle
Get or Set Client Sync Latency
Section titled “Get or Set Client Sync Latency”Adjust delay offset (in ms) to align speakers in space.
- Method:
GET|PUT - Endpoint:
/api/v1/clients/{client_index}/latency - Request Body (PUT): Integer ms delay (e.g.
45).
Switch Client Zone Mapping
Section titled “Switch Client Zone Mapping”Assigns a client speaker to a different audio zone.
- Method:
GET|PUT - Endpoint:
/api/v1/clients/{client_index}/zone - Request Body (PUT): Target zone index (JSON Integer, e.g.
2). - Response
200 OK:2
Client Properties and Status
Section titled “Client Properties and Status”Additional helper endpoints to fetch or update properties and state for a specific speaker client.
-
Method:
GET -
Endpoint:
/api/v1/clients/count -
Response
200 OK: Returns the total number of configured clients as a JSON integer. -
Method:
GET -
Endpoint:
/api/v1/clients/{client_index} -
Response
200 OK: Returns the fullClientInfoobject for the specified index. -
Method:
GET|PUT -
Endpoint:
/api/v1/clients/{client_index}/name -
Request Body (PUT): JSON string with the new friendly name.
-
Response
200 OK: Returns the updated client name. -
Method:
GET -
Endpoint:
/api/v1/clients/{client_index}/icon -
Response
200 OK: Returns the client’s visual icon tag as a JSON string. -
Method:
GET -
Endpoint:
/api/v1/clients/{client_index}/connected -
Response
200 OK: Returns a JSON boolean indicating if the client is currently online and streaming.
7. Client-Side DSP & Speaker Correction
Section titled “7. Client-Side DSP & Speaker Correction”Native SnapDog client boards feature local DSP chips. The server can push filters directly to the client hardware, separating room correction EQs from user EQ settings.
Client Parametric EQ
Section titled “Client Parametric EQ”Query or modify the user-configured EQ applied locally on the client player board.
- Method:
GET|PUT - Endpoint:
/api/v1/clients/{client_index}/eq - Response / Request Body: Same structure as Zone-level EQ. Supports up to 10 bands.
Modify Single EQ Band on Client
Section titled “Modify Single EQ Band on Client”- Method:
PUT - Endpoint:
/api/v1/clients/{client_index}/eq/{band_index} - Request Body:
{ "freq": 1000, "q": 1.0, "gain": -1.5, "type": "peaking" }
Apply Client Preset
Section titled “Apply Client Preset”- Method:
POST - Endpoint:
/api/v1/clients/{client_index}/eq/preset - Request Body:
"loudness"
8. Spinorama Speaker Correction Database
Section titled “8. Spinorama Speaker Correction Database”SnapDog embeds the Spinorama measurement library. You can select your speaker model to retrieve and apply matching parametric correction coefficients.
List Available Speaker Profiles
Section titled “List Available Speaker Profiles”- Method:
GET - Endpoint:
/api/v1/speakers - Response
200 OK: Array of speaker name strings.
Fetch PEQ Coefficients for Model
Section titled “Fetch PEQ Coefficients for Model”- Method:
GET - Endpoint:
/api/v1/speakers/{name}/profile - Response
200 OK: ReturnsEqConfiggenerated from the Spinorama profile curves.
Get Active Speaker Correction on Client
Section titled “Get Active Speaker Correction on Client”- Method:
GET - Endpoint:
/api/v1/clients/{client_index}/speaker
Apply Speaker Correction to Client
Section titled “Apply Speaker Correction to Client”Sets either a predefined Spinorama speaker model, or applies custom correction filters.
- Method:
PUT - Endpoint:
/api/v1/clients/{client_index}/speaker - Request Body: Provide exactly one of
speakername or acustomfilter block:or{"speaker": "Genelec 8030C"}{"custom": {"enabled": true,"bands": [{ "freq": 80, "q": 1.41, "gain": -3.2, "type": "peaking" }]}}
9. KNX Integration
Section titled “9. KNX Integration”If the SnapDog daemon is running in KNX device mode, it functions as an ETS-programmable device. These endpoints manage its KNX hardware configuration.
Download the Embedded ETS Product Database
Section titled “Download the Embedded ETS Product Database”Downloads the exact .knxprod archive embedded in the running server. This is
available even when KNX device mode is inactive, allowing commissioning tools to
obtain the product definition that matches the firmware.
- Method:
GET - Endpoint:
/api/v1/knx/knxprod - Content-Type:
application/octet-stream - Filename:
snapdog.knxprod
Get ETS Product Identity
Section titled “Get ETS Product Identity”Returns the application version, application/order number, and hardware revision of the embedded product database.
- Method:
GET - Endpoint:
/api/v1/knx/product-info - Response
200 OK:{"app_version": 11,"application_number": "0xFF01","hardware_version": 1}
Get or Set ETS Programming Mode
Section titled “Get or Set ETS Programming Mode”Activates or deactivates the physical button programming state (equivalent to pressing the physical programming button on a DIN rail module) to allow the ETS software to assign an individual address.
- Method:
GET|PUT - Endpoint:
/api/v1/knx/programming-mode - Request Body (PUT):
trueorfalse - Response
200 OK:true - Response
409 Conflict: If the server is configured in client mode instead of device mode.{"error": "conflict","message": "KNX device mode not active"}
10. Media & Subsonic Playlists
Section titled “10. Media & Subsonic Playlists”SnapDog integrates with internet radio streams and Subsonic-compatible servers (e.g. Navidrome, Gonic). These endpoints allow retrieving and browsing playlists, tracks, and associated cover art.
Playlist identity: playlist_id and index
Section titled “Playlist identity: playlist_id and index”Every playlist has two identifiers:
| Field | Meaning | Use it for |
|---|---|---|
playlist_id |
Stable reference: snapdog:radio for the radio list, subsonic:<subsonic id> for a Subsonic playlist. |
Remembering a selection, comparing, “currently playing”, keys of lists, the by-id endpoints. |
index |
Zero-based position in the unified list. | Addressing an index endpoint immediately after reading the list. |
The index moves when a playlist is created or removed in Subsonic, when radio stations are configured or removed, and for a short time while the Subsonic server cannot be reached. Never store an index, store the playlist_id.
A client that finds no playlist_id and no index in a playlist talks to an older server and may fall back to id.
List Unified Playlists
Section titled “List Unified Playlists”Returns a list of all playlists available, combining the local Radio streams list (index 0) and all Subsonic server playlists (indices 1 and higher).
- Method:
GET - Endpoint:
/api/v1/media/playlists - Response
200 OK:The response is an array of such objects. The radio list is the first element, with{"id": 1,"index": 1,"playlist_id": "subsonic:42","name": "My Acoustic Playlist","song_count": 5,"duration": 1200,"cover_art": "/api/v1/media/playlists/1/cover"}"index": 0and"playlist_id": "snapdog:radio".idis deprecated and repeatsindex.
The list changes when Subsonic playlists change. SnapDog reads the Subsonic list every [subsonic].refresh_secs seconds (default 60, 0 turns the background read off, see configuration) and sends the WebSocket event playlists_changed when something changed. Reload this endpoint after that event and after every WebSocket reconnect.
Get Playlist Details
Section titled “Get Playlist Details”- Method:
GET - Endpoints:
/api/v1/media/playlists/{playlist_index}— takes the index./api/v1/media/playlists/by-id/{playlist_id}— takes theplaylist_id(percent-encoded). An unknownplaylist_idreturns404 Not Found.
- Response
200 OK:{"id": 1,"index": 1,"playlist_id": "subsonic:42","name": "My Acoustic Playlist","tracks": 5}idis deprecated and repeatsindex.
Get Playlist Cover Art
Section titled “Get Playlist Cover Art”Returns the cover image binary (PNG/JPEG/GIF) for the specified playlist.
- Method:
GET - Endpoint:
/api/v1/media/playlists/{playlist_index}/cover - Response
200 OK: Raw image bytes (Content-Type: image/*).
List Tracks in Playlist
Section titled “List Tracks in Playlist”Returns the list of tracks belonging to the specified playlist.
- Method:
GET - Endpoints:
/api/v1/media/playlists/{playlist_index}/tracks— takes the index./api/v1/media/playlists/by-id/{playlist_id}/tracks— takes theplaylist_id(percent-encoded).
- Query parameters (both endpoints):
limit(maximum number of tracks) andoffset(tracks to skip, default0). With either one, the same array is cut and the response headerX-Total-Countcarries the full number of tracks. Without both, the whole list is returned and noX-Total-Countheader is sent. - Response
200 OK:[{"id": "subsonic_track_101","title": "Acoustic Song","artist": "The Band","album": "Unplugged","duration": 240,"track": 1,"cover_art": "/api/v1/media/playlists/1/tracks/0/cover"}]
Get Track Details
Section titled “Get Track Details”- Method:
GET - Endpoint:
/api/v1/media/playlists/{playlist_index}/tracks/{track_index} - Response
200 OK: (Returns the track object depicted in the list above)
Get Track Cover Art
Section titled “Get Track Cover Art”- Method:
GET - Endpoint:
/api/v1/media/playlists/{playlist_index}/tracks/{track_index}/cover - Response
200 OK: Raw image bytes (Content-Type: image/*).
Search the Library, the Playlists and the Radio Stations
Section titled “Search the Library, the Playlists and the Radio Stations”Searches four kinds at once: tracks and albums of the Subsonic server, playlists, and radio stations. Tracks and albums come from the search3 call of the Subsonic server, so what matches follows the rules of that server (some match word prefixes, some any substring). Playlists and radio stations are matched by SnapDog on a case-insensitive substring of the name.
-
Method:
GET -
Endpoint:
/api/v1/media/search -
Query parameters:
q(required): text to search for, at least two characters.kind: comma-separated kinds out oftrack,album,playlistandradio. The default is all four.limit: results per kind. The default is20, the maximum100.offset: results to skip per kind. The default is0.
-
Response
200 OK:{"items": [{"kind": "track","title": "Acoustic Song","subtitle": "The Band","duration": 240,"track_id": "101","cover_art": "/api/v1/media/cover/al-7"},{"kind": "album","title": "Unplugged","subtitle": "The Band","duration": 2400,"album_id": "7","cover_art": "/api/v1/media/cover/al-7"},{"kind": "playlist","title": "My Acoustic Playlist","duration": 1200,"playlist_id": "subsonic:42","index": 1}],"next_offset": null}A result has one identifier field for its kind and no generic
id:kindIdentifier Play it with tracktrack_idPOST /api/v1/zones/{zone_index}/play/subsonic/{track_id}albumalbum_idPOST /api/v1/zones/{zone_index}/play/subsonic/album/{album_id}playlistplaylist_idandindexPOST /api/v1/zones/{zone_index}/play/playlist/by-idradioplaylist_id(snapdog:radio),indexandtrackPOST /api/v1/zones/{zone_index}/play/playlist/by-idwith thetrackof the resultsearch3reports no total, so there is no total here either.next_offsetis the offset of the next page and isnullwhen no kind filled its page. -
Errors:
400 Bad Requestfor aqshorter than two characters or an unknownkind, and502 Bad Gatewaywhen the Subsonic server fails.
Get a Cover by its Cover Id
Section titled “Get a Cover by its Cover Id”A search result has no playlist index to build a playlist cover path from. This endpoint proxies the cover of a result by its Subsonic cover id, with the caching headers of the other cover routes.
- Method:
GET - Endpoint:
/api/v1/media/cover/{cover_id}, with the cover id percent-encoded. - Response
200 OK: Raw image bytes (Content-Type: image/*). - Errors:
404 Not Foundwhen the cover does not exist, and503 Service Unavailablewhen Subsonic is not configured.
Play a Subsonic Album
Section titled “Play a Subsonic Album”Queues the tracks of the album and starts the first one. An album is not part of the unified playlist list, so the zone state names it in playlist_name and has no playlist_index and no playlist_id. A search result of the kind album carries the album_id.
- Method:
POST - Endpoint:
/api/v1/zones/{zone_index}/play/subsonic/album/{album_id} - Response
200 OK: Empty body.404 Not Foundwhen the zone does not exist.
Create and Change Subsonic Playlists
Section titled “Create and Change Subsonic Playlists”These endpoints write to the Subsonic server, within the rights of the Subsonic user in the configuration. They are off by default. Set [subsonic].playlist_write = true to turn them on (see configuration). Authentication is optional in SnapDog, so with this on anyone who can reach the API can change the playlists of the music library. While it is off, every endpoint here answers 403 Forbidden with the error read_only. The radio list snapdog:radio is never writable through the API and always answers 403.
Creating or deleting a playlist moves the indices of the playlists behind it. Address a playlist by its playlist_id. SnapDog sends the WebSocket event playlists_changed after every write.
| Method and endpoint | Purpose |
|---|---|
POST /api/v1/media/playlists |
Create a playlist. Answers 201 Created with the new playlist as PlaylistInfo. |
PATCH /api/v1/media/playlists/by-id/{playlist_id} |
Rename, append tracks and remove tracks by position, in one call. Answers 200 OK with PlaylistDetails. |
PUT /api/v1/media/playlists/by-id/{playlist_id}/tracks |
Replace the complete content and the order. Answers 200 OK with PlaylistDetails. |
DELETE /api/v1/media/playlists/by-id/{playlist_id} |
Delete a playlist. Answers 204 No Content. The playlists behind it move up by one index. |
Request body of the POST:
{ "name": "Evening", "track_ids": ["101", "102"]}Request body of the PATCH. All three keys are optional, and at least one must be set:
{ "name": "Late Evening", "add_track_ids": ["103"], "remove_positions": [0]}remove_positions are 0-based positions in the playlist as it is now. A zone that plays the playlist keeps its current track and uses the new content from the next track on.
Request body of the PUT:
{ "track_ids": ["102", "101", "103"]}Errors: 400 Bad Request for an empty name or a PATCH with nothing to change, 404 Not Found for an unknown playlist_id, 502 Bad Gateway when the Subsonic server refuses or fails, and 503 Service Unavailable when Subsonic is not configured.