Skip to main content

Ampache REST API

RESTful Resource Path Conversion in Ampache

As part of the ongoing modernisation of the Ampache API, the project has created a fully resource-oriented RESTful specification aligned with OpenAPI based on the query-parameter based RPC model.

The OpenApi specs are documented here Ampache REST API

This document explains:

  • The differences between the RPC API and the RESTful API
  • Which OpenAPI specification to use for your API version
  • How resource path conversion works
  • Updated endpoint structure and behaviour
  • HTTP method alignment
  • Versioning model
  • Migration guidance

OpenAPI Specifications

A separate specification is published for each documented REST surface. Use the version selector at the top of the Swagger UI to switch between them, or point your own tooling straight at the raw JSON.

SpecificationRaw specAPI versionServed by
Ampache API 8 (current)openapi.json8 (also describes 3, 4, 5, 6 as server variables)Ampache 8
Ampache API 6openapi-6.json6Ampache 7 and Ampache 8

Both specs are OpenAPI 3.0.3, share the same {ampacheUrl}/rest/{version}/{format} server template, and use the same authentication schemes (auth header, auth query parameter, or a Bearer token).

Which spec should I use?

  • Targeting Ampache 8 and happy to require it — use openapi.json. It is the canonical document for the current API and the only one describing the API8-only paths.
  • Targeting Ampache 7 and Ampache 8 from the same client — use openapi-6.json. It is pinned to API version 6 and deliberately describes only the surface both servers honour.

Differences in the API 6 specification

  • The apiVersion server variable is locked to 6. There is no way to accidentally generate an API8 client from it.
  • API8-only paths are absent: /folder, /folders and /playlists/{playlist_id}/remove. /random is also absent — API6 serves it on Ampache 8 but not on Ampache 7.
  • Only success responses are documented. API versions 3-6 always return HTTP 200 and carry any error in the response body, unlike API version 8 which returns real HTTP status codes. See API Errors for the error payload shape.
  • Response schemas come from the API6 data builders, so field names and types match what an Ampache 7 server actually emits.

The API 6 spec is maintained by hand alongside the server code and is guarded by a conformance test in the Ampache repository (tests/Module/Api/Api6SpecConformanceTest.php), which fails if the running code drifts from the published document.

Background

Ampache historically exposed its API through two server entry points providing XML and JSON output formats:

https://demo.ampache.dev/server/xml.server.php?action={action_name}&parameter=value
https://demo.ampache.dev/server/json.server.php?action={action_name}&parameter=value

While functional, this approach:

  • Mixes transport and action logic
  • Encodes behaviour inside query parameters
  • Overloads GET for state-changing operations
  • Limits proper HTTP semantics
  • Reduces cache effectiveness
  • Complicates OpenAPI documentation

The new RESTful API resolves these issues by introducing structured, versioned resource paths.

RPC API Structure

Pattern

{ampacheURL}/server/{format}.server.php?action={action}&{parameters}

Characteristics:

  • Behaviour determined by the action parameter
  • Primarily GET-based
  • Resources inferred indirectly
  • Verb-style operation naming

Example:

https://demo.ampache.dev/server/xml.server.php?action=song&id=123
https://demo.ampache.dev/server/json.server.php?action=playlist_songs&id=9
https://demo.ampache.dev/server/xml.server.php?action=add_song&playlist=9&song=123

RESTful Resource Path Structure

Key characteristics:

  • Resource-oriented URL design
  • Plural resource naming
  • Hierarchical relationship modelling
  • Proper HTTP verb usage
  • OpenAPI-compliant specification
  • Clear separation between transport and intent

Base Path

All REST urls require the API version and format as part of the base url.

{ampacheURL}/rest/{version}/{format}

e.g. https://demo.ampache.dev/rest/8/json

Resources and Items

You access objects from resource paths.

{ampacheURL}/rest/{version}/{format}/{resource}

e.g. https://demo.ampache.dev/rest/8/json/albums

Resources can them be filtered into individual items.

{ampacheURL}/rest/{version}/{format}/{resource}/{identifier}

e.g. https://demo.ampache.dev/rest/8/json/albums/21

Nested Resource

When you've filtered to an individual resource you can perform actions on that resource or fetch children of the object.

{ampacheURL}/rest/{version}/{format}/{parent}/{id}/{child}

e.g. https://demo.ampache.dev/rest/8/json/albums/21/songs

REST path to RPC call map

If you're struggling to map the new paths to actions this table will allow you to ID the calls you want to make using the old RPC methods.

All REST path URLs are prefixed with the Ampache Base Path to make sure you are given the correct format and version response.

e.g. To make a REST call for 10 random albums your URL would be https://demo.ampache.dev/rest/8/json/albums/?limit=10&sort=rand

HTTPRESTRPC actionAlternative action
GETalbums/{album_id}/art?action=get_art&filter={album_id}&type=album
GETalbums/{album_id}/fetch-metadata?action=get_external_metadata&filter={album_id}&type=album
POSTalbums/{album_id}/flag?action=flag&filter={album_id}&type=album
POSTalbums/{album_id}/rate?action=rate&filter={album_id}&type=album
POSTalbums/{album_id}/share?action=share&filter={album_id}&type=album
GETalbums/{album_id}/songs?action=album_songs&filter={album_id}&type=album
POSTalbums/{album_id}/update-art?action=update_art&filter={album_id}&type=album
POSTalbums/{album_id}/update-tags?action=update_from_tags&filter={album_id}&type=album
GETalbums/{album_id}?action=album&filter={album_id}
GETalbums/search?action=search&type=album `advanced_search
GETalbums/stats?action=stats&type=album
GETalbums?action=albums
GETartists/{artist_id}/albums?action=artist_albums&filter={artist_id}
GETartists/{artist_id}/art?action=get_art&filter={artist_id}&type=artist
POSTartists/{artist_id}/fetch-info?action=update_artist_info&filter={artist_id}&type=artist
GETartists/{artist_id}/fetch-metadata?action=get_external_metadata&filter={artist_id}&type=artist
POSTartists/{artist_id}/flag?action=flag&filter={artist_id}&type=artist
POSTartists/{artist_id}/rate?action=rate&filter={artist_id}&type=artist
POSTartists/{artist_id}/share?action=share&filter={artist_id}&type=artist
GETartists/{artist_id}/similar?action=get_similar&filter={artist_id}&type=artist
GETartists/{artist_id}/songs?action=artist_songs&filter={artist_id}&type=artist
POSTartists/{artist_id}/update-art?action=update_art&filter={artist_id}&type=artist
POSTartists/{artist_id}/update-tags?action=update_from_tags&filter={artist_id}&type=artist
GETartists/{artist_id}?action=artist&filter={artist_id}
GETartists/search?action=search&type=artistadvanced_search
GETartists/stats?action=stats&type=artist
GETartists?action=artists
GETbookmarks/{bookmark_id}?action=bookmark&filter={bookmark_id}
PATCHbookmarks/{bookmark_id}?action=bookmark_edit&filter={bookmark_id}
DELETEbookmarks/{bookmark_id}?action=bookmark_delete&filter={bookmark_id}
GETbookmarks?action=bookmarks
PUTbookmarks?action=bookmark_create&filter={object_id}&type={object_type}
GETbrowse?action=browse
POSTcatalogs/{catalog_id}/action?action=catalog_action&filter={catalog_id}&task={task}
POSTcatalogs/{catalog_id}/add?action=catalog_action&filter={catalog_id}&task=add_to_catalog
GETcatalogs/{catalog_id}/browse/albums/{album_id}?action=browse&filter={album_id}&type=album&catalog={catalog_id}
GETcatalogs/{catalog_id}/browse/artists/{artist_id}?action=browse&filter={artist_id}&type=artist&catalog={catalog_id}
GETcatalogs/{catalog_id}/browse/podcasts/{podcast_id}?action=browse&filter={podcast_id}&type=podcast&catalog={catalog_id}
GETcatalogs/{catalog_id}/browse?action=browse&filter={catalog_id}&type=catalog
POSTcatalogs/{catalog_id}/clean?action=catalog_action&filter={catalog_id}&task=clean_catalog
POSTcatalogs/{catalog_id}/file?action=catalog_file&filter={catalog_id}
POSTcatalogs/{catalog_id}/folder?action=catalog_folder&filter={catalog_id}
POSTcatalogs/{catalog_id}/update?action=catalog_action&filter={catalog_id}&task=update_catalog
POSTcatalogs/{catalog_id}/verify?action=catalog_action&filter={catalog_id}&task=verify_catalog
GETcatalogs/{catalog_id}?action=catalog&filter={catalog_id}
DELETEcatalogs/{catalog_id}?action=catalog_delete&filter={catalog_id}
GETcatalogs?action=catalogs
PUTcatalogs?action=catalog_create `catalog_add
POSTdemocratic/{object_id}/localplay?action=localplay&command=add&filter={object_id}&type=democratic
POSTdemocratic/{object_id}?action=democratic&filter={object_id}
GETfolder?action=folder
GETfolders?action=folders
GETgenres/{genre_id}/albums?action=genre_albums&filter={genre_id}
GETgenres/{genre_id}/artists?action=genre_artists&filter={genre_id}
GETgenres/{genre_id}/songs?action=genre_songs&filter={genre_id}
GETgenres/{genre_id}?action=genre&filter={genre_id}
GETgenres/search?action=search&type=genreadvanced_search
GETgenres?action=genres
POSTgoodbye?action=goodbye
POSThandshake?action=handshake
GETindex?action=index
GETlabels/{label_id}/artists?action=label_artists&filter={label_id}
GETlabels/{label_id}/fetch-metadata?action=get_external_metadata&filter={label_id}&type=label
GETlabels/{label_id}?action=label&filter={label_id}
GETlabels/search?action=search&type=labeladvanced_search
GETlabels?action=labels
GETlicenses/{license_id}/songs?action=license_songs&filter={license_id}
GETlicenses/{license_id}?action=license&filter={license_id}
GETlicenses?action=licenses
GETlist?action=list
POSTlive-streams/{live_stream_id}/localplay?action=localplay&command=add&filter={live_stream_id}&type=live_stream
GETlive-streams/{live_stream_id}?action=live_stream&filter={live_stream_id}
PATCHlive-streams/{live_stream_id}?action=live_stream_edit&filter={live_stream_id}
DELETElive-streams/{live_stream_id}?action=live_stream_delete&filter={live_stream_id}
GETlive-streams?action=live_streams
PUTlive-streams?action=live_stream_create
POSTlocalplay/add?action=localplay&command=add&filter={object_id}&type={object_type}
POSTlocalplay/delete-all?action=localplay&command=delete_all
POSTlocalplay/next?action=localplay&command=next
POSTlocalplay/pause?action=localplay&command=pause
POSTlocalplay/play?action=localplay&command=play
POSTlocalplay/prev?action=localplay&command=prev
POSTlocalplay/skip?action=localplay&command=skip
GETlocalplay/status?action=localplay&command=status
POSTlocalplay/stop?action=localplay&command=stop
POSTlocalplay/volume-down?action=localplay&command=volume_down
POSTlocalplay/volume-mute?action=localplay&command=volume_mute
POSTlocalplay/volume-up?action=localplay&command=volume_up
GETme/friends-timeline?action=friends_timeline
GETme/last-shouts?action=last_shouts
GETme/lost-password?action=lost_password
GETme/now-playing?action=now_playing
GETme/playlists?action=user_playlists
GETme/smartlists?action=user_smartlists
GETme?action=user
GETping?action=ping
POSTplaylists/{playlist_id}/add?action=playlist_add&filter={playlist_id}
GETplaylists/{playlist_id}/art?action=get_art&filter={playlist_id}&type=playlist
GETplaylists/{playlist_id}/download?action=download&filter={playlist_id}&type=playlist
POSTplaylists/{playlist_id}/flag?action=flag&filter={playlist_id}
GETplaylists/{playlist_id}/hash?action=playlist_hash&filter={playlist_id}
POSTplaylists/{playlist_id}/rate?action=rate&filter={playlist_id}
POSTplaylists/{playlist_id}/remove-song?action=playlist_remove_song&filter={playlist_id}&song={song_id}
POSTplaylists/{playlist_id}/remove?action=playlist_remove&filter={playlist_id}&id={object_id}&type={object_type}
POSTplaylists/{playlist_id}/share?action=share&filter={playlist_id}
GETplaylists/{playlist_id}/songs?action=playlist_songs&filter={playlist_id}
GETplaylists/{playlist_id}/stream?action=stream&filter={playlist_id}&type=playlist
GETplaylists/{playlist_id}?action=playlist&filter={playlist_id}
PATCHplaylists/{playlist_id}?action=playlist_edit&filter={playlist_id}
DELETEplaylists/{playlist_id}?action=playlist_delete&filter={playlist_id}
GETplaylists/search?action=search&type=playlistadvanced_search
GETplaylists/stats?action=stats&type=playlist
GETplaylists?action=playlists
PUTplaylists?action=playlist_create
PUTpodcast-episodes/{episode_id}/bookmark?action=bookmark_create&filter={episode_id}&type=podcast_episode
GETpodcast-episodes/{episode_id}/download?action=download&filter={episode_id}&type=podcast_episode
POSTpodcast-episodes/{episode_id}/flag?action=flag&filter={episode_id}&type=podcast_episode
POSTpodcast-episodes/{episode_id}/localplay?action=localplay&command=add&filter={episode_id}&type=podcast_episode
POSTpodcast-episodes/{episode_id}/playback?action=player&filter={episode_id}&type=podcast_episode
POSTpodcast-episodes/{episode_id}/rate?action=rate&filter={episode_id}&type=podcast_episode
POSTpodcast-episodes/{episode_id}/share?action=share&filter={episode_id}&type=podcast_episode
GETpodcast-episodes/{episode_id}/stream?action=stream&filter={episode_id}&type=podcast_episode
GETpodcast-episodes/{episode_id}?action=podcast_episode&filter={episode_id}
DELETEpodcast-episodes/{episode_id}?action=podcast_episode_delete&filter={episode_id}
GETpodcast-episodes/deleted?action=deleted_podcast_episodes
GETpodcast-episodes/search?action=search&type=podcast_episodeadvanced_search
GETpodcast-episodes/stats?action=stats&type=podcast_episode
GETpodcast-episodes?action=podcast_episodes
GETpodcasts/{podcast_id}/art?action=get_art&filter={podcast_id}&type=podcast
POSTpodcasts/{podcast_id}/flag?action=flag&filter={podcast_id}
GETpodcasts/{podcast_id}/podcast-episodes?action=podcast_episodes&filter={podcast_id}
POSTpodcasts/{podcast_id}/rate?action=rate&filter={podcast_id}
POSTpodcasts/{podcast_id}/share?action=share&filter={podcast_id}
POSTpodcasts/{podcast_id}/refresh?action=podcast_update&filter={podcast_id} `update_podcast
GETpodcasts/{podcast_id}?action=podcast&filter={podcast_id}
PATCHpodcasts/{podcast_id}?action=podcast_edit&filter={podcast_id}
DELETEpodcasts/{podcast_id}?action=podcast_delete&filter={podcast_id}
GETpodcasts/search?action=search&type=podcastadvanced_search
GETpodcasts/stats?action=stats&type=podcast
GETpodcasts?action=podcasts
PUTpodcasts?action=podcast_create
GETpreferences/{preference_name}?action=user_preference&filter={preference_name} `preferences
PATCHpreferences/{preference_name}?action=preference_edit&filter={preference_name}
DELETEpreferences/{preference_name}?action=preference_delete&filter={preference_name}
GETpreferences?action=user_preferences `preferences
PUTpreferences?action=preference_create
POSTregister?action=register
POSTscrobble?action=scrobble
GETsearch/{search_type}/groups?action=search_group&filter={search_type}
GETsearch/{search_type}/rules?action=search_rules&filter={search_type}
GETshares/{share_id}?action=share&filter={share_id}
PATCHshares/{share_id}?action=share_edit&filter={share_id}
DELETEshares/{share_id}?action=share_delete&filter={share_id}
GETshares?action=shares
PUTshares?action=share_create
GETsmartlists/{smartlist_id}/art?action=get_art&filter={smartlist_id}&type=smartlist
GETsmartlists/{smartlist_id}/download?action=download&filter={smartlist_id}&type=smartlist
POSTsmartlists/{smartlist_id}/flag?action=flag&filter={smartlist_id}&type=smartlist
POSTsmartlists/{smartlist_id}/rate?action=rate&filter={smartlist_id}&type=smartlist
POSTsmartlists/{smartlist_id}/share?action=share&filter={smartlist_id}&type=smartlist
GETsmartlists/{smartlist_id}/songs?action=smartlist_songs&filter={smartlist_id}
GETsmartlists/{smartlist_id}/stream?action=stream&filter={smartlist_id}&type=smartlist
GETsmartlists/{smartlist_id}?action=smartlist&filter={smartlist_id}
DELETEsmartlists/{smartlist_id}?action=smartlist_delete&filter={smartlist_id}
GETsmartlists/search?action=search&type=smartlistadvanced_search
GETsmartlists?action=smartlists
GETsongs/{song_id}/art?action=get_art&filter={song_id}&type=song
PUTsongs/{song_id}/bookmark?action=bookmark_create&filter={song_id}&type=song
GETsongs/{song_id}/download?action=download&filter={song_id}
GETsongs/{song_id}/fetch-metadata?action=get_external_metadata&filter={song_id}&type=song
POSTsongs/{song_id}/flag?action=flag&filter={song_id}
POSTsongs/{song_id}/localplay?action=localplay&command=add&filter={song_id}&type=song
GETsongs/{song_id}/lyrics?action=get_lyrics&filter={song_id}
POSTsongs/{song_id}/playback?action=player&filter={song_id}&type=song
POSTsongs/{song_id}/rate?action=rate&filter={song_id}
POSTsongs/{song_id}/record-play?action=record_play&filter={song_id}
POSTsongs/{song_id}/share?action=share&filter={song_id}
GETsongs/{song_id}/similar?action=get_similar&filter={song_id}&type=song
GETsongs/{song_id}/stream?action=stream&filter={song_id}&type=song
GETsongs/{song_id}/tags?action=song_tags&filter={song_id}
POSTsongs/{song_id}/update-tags?action=update_from_tags&filter={song_id}&type=song
GETsongs/{song_id}?action=song&filter={song_id}
DELETEsongs/{song_id}?action=song_delete&filter={song_id}
GETsongs/deleted?action=deleted_songs
GETsongs/lookup/url-to-song?action=url_to_song
GETsongs/playlist-generate?action=playlist_generate
GETsongs/search?action=search&type=songadvanced_search
GETsongs/stats?action=stats&type=song
GETsongs?action=songs
GETsystem-preferences/{preference_name}?action=system_preference&filter={preference_name}
GETsystem-preferences?action=system_preferences
GETupdate?action=system_update
POSTusers/{user_id}/follow?action=toggle_follow&filter={user_id}
GETusers/{user_id}/followers?action=followers&filter={user_id}
GETusers/{user_id}/following?action=following&filter={user_id}
GETusers/{user_id}/timeline?action=timeline&filter={user_id}
GETusers/{user_id}?action=user&filter={user_id}
PATCHusers/{user_id}?action=user_edit&filter={user_id}
DELETEusers/{user_id}?action=user_delete&filter={user_id}
GETusers/search?action=search&type=useradvanced_search
GETusers?action=users
PUTusers?action=user_create
PUTvideos/{video_id}/bookmark?action=bookmark_create&filter={video_id}&type=video
POSTvideos/{video_id}/flag?action=flag&filter={video_id}&type=video
POSTvideos/{video_id}/localplay?action=localplay&command=add&filter={video_id}&type=video
POSTvideos/{video_id}/playback?action=player&filter={video_id}&type=video
POSTvideos/{video_id}/rate?action=rate&filter={video_id}&type=video
POSTvideos/{video_id}/share?action=share&filter={video_id}&type=video
GETvideos/{video_id}?action=video&filter={video_id}
GETvideos/deleted?action=deleted_videos
GETvideos/search?action=search&type=videoadvanced_search
GETvideos/stats?action=stats&type=video
GETvideos?action=videos

Updated Conversion Examples

RPC APIRESTful API
?action=song&id=123GET /rest/6/json/songs/123
?action=artist&id=45GET /rest/6/json/artists/45
?action=album&id=78GET /rest/6/json/albums/78
?action=artistsGET /rest/6/json/artists
?action=playlist_songs&id=9GET /rest/6/json/playlists/9/songs
?action=add_song&playlist=9&song=123POST /rest/6/json/playlists/9/songs

HTTP Method Alignment

The RESTful API uses standard HTTP semantics:

MethodPurposeExample
GETRetrieve resource or collection/rest/6/json/songs/123
POSTCreate resource or relationship/rest/6/json/playlists
PUTReplace full resource/rest/6/json/songs/123
PATCHPartial update/rest/6/json/songs/123
DELETERemove resource/rest/6/json/playlists/9

State-changing behaviour is no longer implemented via GET.

Resource Naming Conventions

To ensure consistency across the API:

  • Use plural nouns for collections
    • songs
    • artists
    • albums
    • playlists
  • Use nested routes for relationships
    • artists/{id}/albums
    • albums/{id}/songs
    • playlists/{id}/songs
  • Avoid verbs in URLs
  • Use HTTP methods to express intent

Versioning Strategy

All RESTful endpoints are prefixed with:

/rest/{version}/{format}

Example

/rest/6/json/songs
/rest/6/xml/artists/45

Versioning enables:

  • Backward compatibility
  • Parallel support for RPC endpoints
  • Incremental evolution of the API
  • Clear OpenAPI documentation per version

Each documented version has its own OpenAPI document; see OpenAPI Specifications for which one to generate your client from.

Authentication and Headers

The RESTful API aligns with OpenAPI specification standards and expects:

  • Authentication token passed via headers
  • Proper Content-Type and Accept headers
  • JSON as the primary response format in documentation
  • XML support remains available where specified.

Backwards Compatibility

  • RPC endpoints remain functional
  • RPC actions are marked as deprecated in REST documentation
  • The RPC and REST APIs will coexist

Benefits of RESTful Conversion

Clarity

Endpoints describe the resource being accessed rather than an action being executed.

Predictability

Developers can infer endpoints from resource structure.

Standards Alignment

Fully compatible with OpenAPI tooling and modern REST conventions.

Cache Compatibility

Improved support for HTTP caching layers and reverse proxies.

Tooling Integration

Works seamlessly with:

  • OpenAPI generators
  • SDK generation tools
  • Postman collections
  • Automated testing frameworks

Migration Recommendations

  1. Identify RPC usage in existing integrations
  2. Map each action to its RESTful resource equivalent
  3. Replace query-based calls with proper HTTP verbs
  4. Update authentication handling to header-based tokens
  5. Validate against the OpenAPI schema

Conversion Rules

  • RPC endpoints must remain accessible and fully functional
  • REST documentation reflects canonical behaviour
  • Separate OpenAPI documentation is maintained for REST endpoints
  • New features must be implemented using RESTful resource paths only

This RESTful specification establishes a cleaner, scalable, and standards-aligned foundation for the Ampache API.