Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/spotify

README.md

166 lines · 9.3 KB · Markdown

@kody/spotify

Official Spotify icon (green circle with three sound waves) from Spotify brand assets.

Intent

Provide reusable, account-agnostic Spotify helpers so Kody can read a connected profile, search the catalog, manage library and playlists, list devices, and control playback.

This listing is meant to be forked. After you fork, connect your Spotify developer app and run ./get-profile on your copy. Do not treat the live @kody/spotify integration as yours. There are no hard-coded personal playlists or account aliases.

When To Use

  • Read the connected user's profile, recently played tracks, top items, or liked songs
  • Search tracks, albums, artists, or playlists
  • List playlists and devices, then start or transfer playback
  • Preview playlist writes and playback changes with dryRun: true

Do not use this package as a Spotify app that other people log into. Spotify Development Mode is for the app owner (and up to five registered users).

Required setup

Spotify has no built-in Kody platform app. You create a personal app in the Spotify developer dashboard and connect it with authorization code + PKCE. PKCE is a public-client flow, so no client secret is stored.

Costs and limits (since February 2026)
  • Development Mode requires the app owner to hold Spotify Premium. If Premium lapses, the app stops working until it is restored.
  • Developers can create up to 25 client IDs; all Development Mode apps share one API quota budget.
  • Refresh tokens expire six months after the original authorization (refreshing an access token does not extend this). Reconnect about twice a year.
  • Some Web API endpoints are unavailable in Development Mode. See the February 2026 migration guide.
  • Extended Quota Mode is only for organizations with at least 250k monthly active users. Personal use stays in Development Mode.
Create the Spotify app
  1. Open the Spotify developer dashboard and click Create app.
  2. Set the redirect URI to exactly https://kody.codes/connect/oauth. Spotify requires HTTPS and rejects localhost.
  3. Select Web API, accept the developer terms, and copy the client ID. With PKCE you do not need the client secret.
  4. Only if someone other than the app owner will authorize: add them under User Management (max 5).
Connect to Kody

flow=pkce is Kody's default, so the link needs no flow parameter and no client secret. Open this URL while signed in to Kody, paste the client ID into the setup form, then authorize.

Guide starter (read-mostly):

https://kody.codes/connect/oauth?provider=spotify&authorizeUrl=https%3A%2F%2Faccounts.spotify.com%2Fauthorize&tokenUrl=https%3A%2F%2Faccounts.spotify.com%2Fapi%2Ftoken&scopes=user-read-recently-played%20user-read-playback-state%20user-library-read&allowedHosts=api.spotify.com

Decoded: authorize https://accounts.spotify.com/authorize, token https://accounts.spotify.com/api/token, scopes user-read-recently-played user-read-playback-state user-library-read, host api.spotify.com.

Recommended for this package (adds profile/top/playlist reads plus playback and library/playlist writes):

https://kody.codes/connect/oauth?provider=spotify&authorizeUrl=https%3A%2F%2Faccounts.spotify.com%2Fauthorize&tokenUrl=https%3A%2F%2Faccounts.spotify.com%2Fapi%2Ftoken&scopes=user-read-recently-played%20user-read-playback-state%20user-read-currently-playing%20user-library-read%20playlist-read-private%20user-top-read%20user-modify-playback-state%20playlist-read-collaborative%20playlist-modify-public%20playlist-modify-private%20user-library-modify&allowedHosts=api.spotify.com

Changing scopes means reconnecting. Reconnect later at https://kody.codes/connect/oauth?provider=spotify (or ?provider=spotify-work).

Access tokens last one hour. Use createAuthenticatedFetch — do not cache raw tokens. Refresh tokens hard-expire six months after the original authorization.

Multiple accounts

Every export accepts optional integration (Kody OAuth connection name). Default is spotify. Extra identities use spotify-* names — for example spotify-work or spotify-kids. Change provider in the connect URL, then pass that name on every call.

import getProfile from 'kody:@kody/spotify/get-profile'

export default async function main() {
	return await getProfile({ integration: 'spotify-work' })
}

Do not hard-code personal aliases such as personal, family, or kent. Those values throw.

Device targeting

Prefer human selectors so opaque Spotify Connect device ids never cross the agent tool boundary:

  1. Happy path — omit device selectors and let Spotify use the active Connect device.
  2. Named device — pass deviceName (case-insensitive substring) and optional deviceType (Speaker, Computer, …).
  3. AdvanceddeviceId still works, but agents should avoid copying ids from get-devices.

Mutations and dryRun

Playlist writes (create-playlist, add-tracks-to-playlist, remove-tracks-from-playlist, follow-playlist, save-tracks) and playback helpers (play-context, play-pause, skip, seek, set-repeat, set-shuffle, set-volume, add-to-queue, transfer-playback) accept dryRun: true. A dry run validates input and returns a preview; Spotify is not written.

import createPlaylist from 'kody:@kody/spotify/create-playlist'

export default async function main() {
	return await createPlaylist({ name: 'Focus', public: false, dryRun: true })
}

Playback control acts on real devices. Use dryRun: true first when the user has not confirmed a live change.

Smoke test

After connect or reconnect, import a helper from this package (not packages.invoke with kodyId: 'spotify'):

import getProfile from 'kody:@kody/spotify/get-profile'

export default async function main() {
	return await getProfile()
}

Success includes id and product for the connected user. product should be premium for Development Mode.

Low-level equivalent (execute exploration only):

import { createAuthenticatedFetch } from 'kody:runtime'

export default async function main() {
	const spotifyFetch = await createAuthenticatedFetch('spotify')
	const response = await spotifyFetch('https://api.spotify.com/v1/me')
	if (!response.ok) {
		throw new Error('Spotify smoke test failed: ' + response.status + ' ' + (await response.text()))
	}
	const me = (await response.json()) as { display_name?: string; id: string; product?: string }
	return { id: me.id, displayName: me.display_name, product: me.product }
}

Exports

  • kody:@kody/spotify — package overview, PKCE connect URLs, and setup notes
  • kody:@kody/spotify/accounts — default integration and spotify-* naming
  • kody:@kody/spotify/get-profile — connected user profile
  • kody:@kody/spotify/search — catalog search
  • kody:@kody/spotify/get-track — track details
  • kody:@kody/spotify/get-saved-tracks — liked/saved library tracks
  • kody:@kody/spotify/save-tracks — save tracks (dryRun supported)
  • kody:@kody/spotify/get-recently-played — listening history
  • kody:@kody/spotify/get-top-items — top tracks or artists
  • kody:@kody/spotify/get-recommendations — seed recommendations (may be unavailable in Development Mode)
  • kody:@kody/spotify/list-playlists — the user's playlists
  • kody:@kody/spotify/get-playlist — playlist summary and track preview
  • kody:@kody/spotify/get-all-playlist-tracks — paginate every playlist track
  • kody:@kody/spotify/create-playlist — create a playlist (dryRun supported)
  • kody:@kody/spotify/add-tracks-to-playlist — add tracks (dryRun supported)
  • kody:@kody/spotify/remove-tracks-from-playlist — remove tracks (dryRun supported)
  • kody:@kody/spotify/follow-playlist — follow a playlist (dryRun supported)
  • kody:@kody/spotify/get-devices — Connect devices (use name with deviceName)
  • kody:@kody/spotify/playback-state — current playback snapshot
  • kody:@kody/spotify/get-queue — current queue
  • kody:@kody/spotify/play-context — start a context (dryRun supported)
  • kody:@kody/spotify/play-pause — toggle play/pause (dryRun supported)
  • kody:@kody/spotify/skip — next or previous (dryRun supported)
  • kody:@kody/spotify/seek — seek (dryRun supported)
  • kody:@kody/spotify/set-repeat / set-shuffle / set-volume (dryRun supported)
  • kody:@kody/spotify/add-to-queue — queue a URI (dryRun supported)
  • kody:@kody/spotify/transfer-playback — move playback (dryRun supported)

Share this listing as https://kody.codes/@kody/spotify.

Troubleshooting

  • INVALID_CLIENT: Invalid redirect URI: the dashboard redirect URI must be exactly https://kody.codes/connect/oauth.
  • 403 User not registered in the Developer Dashboard: add the user under User Management, or have them create their own app.
  • 403 on a specific endpoint: that endpoint may be unavailable in Development Mode.
  • App failing across the board: check that the app owner's Premium subscription is active.
  • 401 after about an hour: access tokens expire hourly. Use createAuthenticatedFetch.
  • invalid_grant about six months after connecting: reconnect at /connect/oauth?provider=spotify.