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 spec is documented here Ampache REST API

This document explains:

  • The differences between the RPC API and the RESTful API
  • How resource path conversion works
  • Updated endpoint structure and behaviour
  • HTTP method alignment
  • Versioning model
  • Migration guidance

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

HTTP METHODRESTRPC actionAlternative action
GETalbums/{album_id}/art?action=get_art&filter={album_id}&type=album
POSTalbums/{album_id}/commands?action={flag|rate|share|update_art|update_from_tags}&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}/commands?action={flag|rate|share|update_art|update_from_tags}&filter={artist_id}&type=artist
GETartists/{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}
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}/commands?action=catalog_action&filter={catalog_id}&task={task}
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
GETgoodbye?action=goodbye
GEThandshake?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/commands?action=localplay&command={command}&filter={object_id}&type={object_type}
GETlocalplay/delete-all?action=localplay&command=delete_all
GETlocalplay/next?action=localplay&command=next
POSTlocalplay/pause?action=localplay&command=pause
GETlocalplay/play?action=localplay&command=play
GETlocalplay/prev?action=localplay&command=prev
GETlocalplay/skip?action=localplay&command=skip
GETlocalplay/status?action=localplay&command=status
POSTlocalplay/stop?action=localplay&command=stop
GETlocalplay/volume-down?action=localplay&command=volume_down
GETlocalplay/volume-mute?action=localplay&command=volume_mute
GETlocalplay/volume-up?action=localplay&command=volume_up
POSTlocalplay?action=localplay
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
POSTplaylists/{playlist_id}/commands?action={playlist_add|playlist_remove|playlist_remove_song}&filter={playlist_id}
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}
POSTpodcast-episodes/{id}/commands?action={flag|rate|share|player|localplay}&filter={id}&type=podcast_episode
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}/commands?action={flag|rate|share|podcast_update}&filter={podcast_id}
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}/update?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
GETscrobble?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
POSTsongs/{song_id}/commands?action={flag|rate|share|player|record_play|localplay}&filter={song_id}
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}/commands?action=toggle_follow&filter={user_id}
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}/commands?action={flag|rate|share|player|localplay}&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

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.