Corsair
PluginsSpotify

Spotify

Integrate Spotify music playback, library, and playlists

Quick Start

Install the plugin:

pnpm install @corsair-dev/spotify

Add the Spotify plugin to your Corsair instance:

corsair.ts
import { createCorsair } from "corsair";
import { spotify } from "@corsair-dev/spotify";

export const corsair = createCorsair({
    plugins: [
        spotify(),
    ],
});

Once configured, you can access the Spotify API:

// Search for tracks
const results = await corsair.spotify.api.tracks.search({
    q: "Bohemian Rhapsody",
    limit: 5,
});

Authentication

Supported Auth Types

The Spotify plugin supports:

  • oauth_2 (default) - Use OAuth 2.0 for user authentication

Default Auth Type

If no authType is specified, the plugin defaults to oauth_2.

Configuring OAuth 2.0 Authentication

Store your Spotify app credentials, then start the OAuth flow:

pnpm corsair setup --spotify client_id=your-client-id client_secret=your-client-secret
pnpm corsair auth --plugin=spotify

The CLI will print an authorization URL — open it in a browser. Once you approve, tokens are saved automatically.

Alternatively, provide credentials directly in the config:

corsair.ts
spotify({
    key: process.env.SPOTIFY_ACCESS_TOKEN,
})

See Authentication for details on setting up OAuth 2.0 credentials.

Options

OptionTypeDescription
authType'oauth_2'Authentication method (defaults to 'oauth_2')
keystringAccess token (optional, uses database if not provided)
hooksobjectEndpoint hooks for custom logic
webhookHooksobjectWebhook hooks for event handling
errorHandlersobjectCustom error handlers
permissionsobjectPermission configuration for AI agent access

Hooks

spotify({
    hooks: {
        player: {
            startPlayback: {
                before: async (ctx, input) => {
                    console.log("Starting playback:", input.context_uri);
                    return { ctx, input };
                },
            },
        },
    },
})

See Hooks for complete documentation.

Error Handling

The plugin includes built-in error handlers for common scenarios. For complete documentation, see the Error Handlers reference.

Usage

Accessing the API

// Get currently playing track
const current = await corsair.spotify.api.player.getCurrentlyPlaying({});

// Create a playlist
const playlist = await corsair.spotify.api.playlists.create({
    name: "My Corsair Playlist",
    description: "Created via Corsair",
    public: false,
});

// Add tracks to playlist
await corsair.spotify.api.playlists.addItem({
    playlist_id: playlist.data.id,
    uris: ["spotify:track:4uLU6hMCjMI75M1A2tKUQC"],
});

See API Endpoints for the complete reference.

Database Access

const tracks = await corsair.spotify.db.tracks.search({
    data: { name: "Bohemian Rhapsody" },
});

See Database for the complete schema.

Multi-Tenancy

const tenant = corsair.withTenant("user-123");

await tenant.spotify.api.player.resume({});

Examples

Example 1: Build a Playlist from Search Results

inngest/functions.ts
export const buildPlaylist = inngest.createFunction(
    { id: "build-spotify-playlist" },
    { event: "app/playlist-requested" },
    async ({ event }) => {
        const tenant = corsair.withTenant(event.data.tenantId);

        const tracks = await tenant.spotify.api.tracks.search({
            q: event.data.genre, 
            limit: 20,
        });

        const playlist = await tenant.spotify.api.playlists.create({
            name: `${event.data.genre} Mix`, 
            public: false,
        });

        await tenant.spotify.api.playlists.addItem({
            playlist_id: playlist.data.id,
            uris: tracks.data.tracks.items.map(t => t.uri), 
        });

        return { playlistId: playlist.data.id };
    }
);

Example 2: Morning Playlist Auto-Play

inngest/functions.ts
export const morningPlaylist = inngest.createFunction(
    { id: "morning-playlist" },
    { cron: "0 7 * * *" },
    async () => {
        const playlists = await corsair.spotify.api.playlists.getUserPlaylists({});

        const morningPlaylist = playlists.data.items.find(
            p => p.name.toLowerCase().includes("morning") 
        );

        if (morningPlaylist) {
            await corsair.spotify.api.player.startPlayback({
                context_uri: morningPlaylist.uri,
            });
        }
    }
);

Example 3: Get Liked Tracks for Recommendations

inngest/functions.ts
export const analyzeListeningHistory = inngest.createFunction(
    { id: "analyze-listening-history" },
    { event: "app/analyze-music" },
    async ({ event }) => {
        const tenant = corsair.withTenant(event.data.tenantId);

        const liked = await tenant.spotify.api.library.getLikedTracks({
            limit: 50, 
        });

        const topArtistIds = [...new Set(
            liked.data.items.map(item => item.track.artists[0].id)
        )].slice(0, 5);

        const relatedArtists = await Promise.all(
            topArtistIds.map(id =>
                tenant.spotify.api.artists.getRelatedArtists({ id })
            )
        );

        return { relatedArtists: relatedArtists.flatMap(r => r.data.artists) };
    }
);