Spotify Web API
Access Spotify's music catalog, manage playlists, control playback, and retrieve personalized listening data via the Spotify Web API.
Official docs:
https://developer.spotify.com/documentation/web-api
When to Use
Use this skill when you need to:
- Search for tracks, albums, artists, or playlists
- Get current user profile and listening stats
- Retrieve the user's top tracks and artists
- List and manage playlists
- Control music playback (requires Spotify Premium)
- Get currently playing track or recent listening history
Prerequisites
Go to vm0.ai Settings → Connectors and connect Spotify. vm0 will automatically inject the required SPOTIFY_TOKEN environment variable.
Important: The Spotify access token expires after 1 hour. If you receive a 401 error, the token needs to be refreshed via the Connector settings.
Note: Playback control endpoints (play, pause, skip) require a Spotify Premium account.
User Profile
Get Current User Profile
curl -s "https://api.spotify.com/v1/me" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '{id, display_name, email, product, followers: .followers.total}'
Search
Search Tracks, Artists, Albums, or Playlists
Write to /tmp/spotify_query.txt:
<your-search-query>
curl -s -G "https://api.spotify.com/v1/search" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" --data-urlencode "q@/tmp/spotify_query.txt" --data-urlencode "type=track,artist,album" -d "limit=5" | jq '{tracks: [.tracks.items[]? | {id, name, artists: [.artists[].name], album: .album.name, uri}], artists: [.artists.items[]? | {id, name, genres, uri}]}'
To search for playlists only:
curl -s -G "https://api.spotify.com/v1/search" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" --data-urlencode "q@/tmp/spotify_query.txt" --data-urlencode "type=playlist" -d "limit=5" | jq '[.playlists.items[]? | {id, name, owner: .owner.display_name, tracks: .tracks.total, uri}]'
Personalized Data
Get Top Tracks
Requires scope: user-top-read.
time_range options: short_term (4 weeks), medium_term (6 months), long_term (all time).
curl -s "https://api.spotify.com/v1/me/top/tracks?limit=20&time_range=medium_term" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '[.items[] | {name, artists: [.artists[].name], album: .album.name, uri}]'
Get Top Artists
Requires scope: user-top-read.
curl -s "https://api.spotify.com/v1/me/top/artists?limit=20&time_range=medium_term" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '[.items[] | {name, genres, popularity, uri}]'
Get Recently Played Tracks
Requires scope: user-read-recently-played.
curl -s "https://api.spotify.com/v1/me/player/recently-played?limit=20" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '[.items[] | {played_at, track: .track.name, artists: [.track.artists[].name], uri: .track.uri}]'
Playlists
List Current User's Playlists
Requires scope: playlist-read-private.
curl -s "https://api.spotify.com/v1/me/playlists?limit=20" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '[.items[] | {id, name, owner: .owner.display_name, total_tracks: .tracks.total, uri}]'
Get Playlist Tracks
Replace <playlist-id> with the actual playlist ID:
curl -s "https://api.spotify.com/v1/playlists/<playlist-id>/tracks?limit=50&fields=items(track(id,name,artists,album(name),uri))" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '[.items[] | {name: .track.name, artists: [.track.artists[].name], album: .track.album.name, uri: .track.uri}]'
Create Playlist
Requires scope: playlist-modify-public or playlist-modify-private.
First, get your user ID:
curl -s "https://api.spotify.com/v1/me" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq -r '.id'
Write to /tmp/spotify_playlist.json:
{
"name": "<your-playlist-name>",
"description": "<your-playlist-description>",
"public": false
}
Replace <user-id> with your Spotify user ID:
curl -s -X POST "https://api.spotify.com/v1/users/<user-id>/playlists" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" --header "Content-Type: application/json" -d @/tmp/spotify_playlist.json | jq '{id, name, uri}'
Add Tracks to Playlist
Requires scope: playlist-modify-public or playlist-modify-private.
Write to /tmp/spotify_add_tracks.json:
{
"uris": [
"spotify:track:<track-id-1>",
"spotify:track:<track-id-2>"
]
}
Replace <playlist-id> with the target playlist ID:
curl -s -X POST "https://api.spotify.com/v1/playlists/<playlist-id>/tracks" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" --header "Content-Type: application/json" -d @/tmp/spotify_add_tracks.json | jq '{snapshot_id}'
Playback Control
Requires Spotify Premium. All playback endpoints need an active Spotify client running on a device.
Get Playback State
Requires scope: user-read-playback-state.
curl -s "https://api.spotify.com/v1/me/player" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '{device: .device.name, is_playing, track: .item.name, artists: [.item.artists[]?.name], progress_ms, duration_ms: .item.duration_ms}'
Start or Resume Playback
Requires scope: user-modify-playback-state.
Play a specific playlist or album by URI:
Write to /tmp/spotify_play.json:
{
"context_uri": "spotify:playlist:<playlist-id>"
}
curl -s -X PUT "https://api.spotify.com/v1/me/player/play" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" --header "Content-Type: application/json" -d @/tmp/spotify_play.json
Play specific tracks by URI:
Write to /tmp/spotify_play.json:
{
"uris": [
"spotify:track:<track-id-1>",
"spotify:track:<track-id-2>"
]
}
curl -s -X PUT "https://api.spotify.com/v1/me/player/play" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" --header "Content-Type: application/json" -d @/tmp/spotify_play.json
Pause Playback
Requires scope: user-modify-playback-state.
curl -s -X PUT "https://api.spotify.com/v1/me/player/pause" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)"
Skip to Next Track
Requires scope: user-modify-playback-state.
curl -s -X POST "https://api.spotify.com/v1/me/player/next" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)"
Skip to Previous Track
Requires scope: user-modify-playback-state.
curl -s -X POST "https://api.spotify.com/v1/me/player/previous" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)"
Set Volume
Requires scope: user-modify-playback-state. Replace <volume> with a value between 0 and 100:
curl -s -X PUT "https://api.spotify.com/v1/me/player/volume?volume_percent=<volume>" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)"
Albums & Artists
Get Album
Replace <album-id> with the Spotify album ID:
curl -s "https://api.spotify.com/v1/albums/<album-id>" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '{id, name, artists: [.artists[].name], release_date, total_tracks, uri}'
Get Artist
Replace <artist-id> with the Spotify artist ID:
curl -s "https://api.spotify.com/v1/artists/<artist-id>" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '{id, name, genres, popularity, followers: .followers.total, uri}'
Get Artist's Top Tracks
Replace <artist-id> with the Spotify artist ID:
curl -s "https://api.spotify.com/v1/artists/<artist-id>/top-tracks" --header "Authorization: Bearer $(printenv SPOTIFY_TOKEN)" | jq '[.tracks[] | {name, album: .album.name, popularity, uri}]'
Guidelines
- Token Expiry: Access tokens expire after 1 hour. A 401 response means the token needs refreshing via the Connector settings.
- Scopes: Different endpoints require different OAuth scopes. Ensure the connected Spotify app has the necessary scopes granted (listed per endpoint above).
- Premium Required: All playback control endpoints (
/me/player/play,/me/player/pause,/me/player/next, etc.) require a Spotify Premium subscription. - Rate Limits: Spotify enforces rate limits. If you receive a 429 response, back off and retry after the
Retry-Afterheader value (in seconds). - Spotify URIs vs IDs: Resources can be referenced by URI (
spotify:track:<id>) or bare ID depending on the endpoint. Search results include bothidandurifields.