TuneCamp exposes a RESTful API for webapp–backend communication, plus dedicated endpoints for ActivityPub and the Subsonic protocol. The full OpenAPI specification is in openapi.yml.
Most endpoints require a JWT (JSON Web Token) in the Authorization header:
Authorization: Bearer <token>
Obtain a token by posting credentials to POST /api/auth/login.
| Method | Path | Description |
|---|---|---|
POST |
/api/users/register |
Register a new user |
POST |
/api/auth/login |
Authenticate and receive a JWT |
GET |
/api/auth/status |
Return the current session and user profile |
| Method | Path | Description |
|---|---|---|
GET |
/api/albums |
List all local albums. Returns status (draft | published) and is_release (boolean) to distinguish library content from official releases |
GET |
/api/albums/:id |
Album details including the track list |
GET |
/api/artists |
List all artists |
POST |
/api/tracks |
Create a track from metadata (a link, or a row awaiting its file). The audio is not fetched: the track is created with no file_path until a file is uploaded for it. There is no localize option here — this server does not download audio from streaming platforms |
GET |
/api/tracks |
List tracks visible to the caller. Each row carries downloadable: whether THIS viewer may take the file, not just stream it (clients offering a download button read it instead of guessing) |
GET |
/api/tracks/:id |
Track metadata |
GET |
/api/tracks/:id/stream |
Binary audio stream (supports Range for cloud tracks) |
GET |
/api/tracks/:id/download |
Download a single track's local audio file. Gated by the release's distribution mode: paid content needs an unlock code (?code=), a recorded purchase or an active subscription (402 otherwise), streaming-only and external-showcase releases answer 403. Staff, the owner and the linked artist bypass it |
POST |
/api/tracks/:id/localize |
Admin-only: copy a cloud-backed track (a gdrive:// path) into a durable local file. Streaming platforms are refused with 400 — use Sidecamp |
GET |
/api/albums/:id/download |
Download a ZIP of the album's local audio files (skips streaming/linked tracks). Same distribution-mode gate as the single-track route |
GET |
/api/releases/:id/download |
Download a ZIP of a release's local audio files. Resolves numeric id or slug; private releases gated to owner/admin, and the same distribution-mode gate as the single-track route applies |
GET |
/api/waveform/:id |
Waveform data for visualisation |
GET |
/api/releases/:id/artwork/:filename |
Serve additional release artwork securely |
| Method | Path | Description |
|---|---|---|
GET |
/api/samples |
List approved samples. mine=true scopes to the caller's own uploads (any status); q filters by search term |
GET |
/api/samples/moderation/pending |
Root-admin/admin/super-user: list samples awaiting curation |
GET |
/api/samples/:id |
Sample metadata |
GET |
/api/samples/:id/download |
Download the sample audio file. Supports ?token= query auth (approved samples are public; pending samples require the owner or a moderator) |
POST |
/api/samples |
Upload a sample (multipart/form-data: file, title, description, bpm, musicalKey, license, attributionName, tags). Starts in pending status |
PUT |
/api/samples/:id |
Update sample metadata (owner or moderator) |
DELETE |
/api/samples/:id |
Delete a sample (owner or moderator) |
POST |
/api/samples/:id/approve |
Root-admin/admin/super-user: approve a pending sample |
POST |
/api/samples/:id/reject |
Root-admin/admin/super-user: reject a pending sample with optional notes |
Free samples are not store assets: no price, no purchase flow, no credits. License is one of cc0, cc-by, cc-by-sa, royalty-free. Upload is reachable from /publish; managing your own uploads is under the "Samples" tab on /my-music; moderation is under "Sample Curation" on /admin.
| Method | Path | Description |
|---|---|---|
GET |
/api/sample-packs |
List approved packs. mine=true scopes to the caller's own packs (any status); q filters by search term |
GET |
/api/sample-packs/moderation/pending |
Root-admin/admin/super-user: list packs awaiting curation |
GET |
/api/sample-packs/:id |
Pack metadata plus its member samples |
GET |
/api/sample-packs/:id/cover |
Pack cover image; falls back to a generated placeholder SVG if none is set |
POST |
/api/sample-packs |
Upload multiple files at once as a pack (multipart/form-data: files[], title, description, license, attributionName). Same publish gate and auto-approve rules as /api/samples; starts in pending unless auto-approved |
POST |
/api/sample-packs/:id/cover |
Set/replace the pack cover image (multipart/form-data: cover). Owner/moderator only |
PUT |
/api/sample-packs/:id |
Update pack metadata (owner or moderator) |
DELETE |
/api/sample-packs/:id |
Delete a pack and all its member samples (owner or moderator) |
POST |
/api/sample-packs/:id/approve |
Root-admin/admin/super-user: approve a pending pack (cascades to its samples) |
POST |
/api/sample-packs/:id/reject |
Root-admin/admin/super-user: reject a pending pack with optional notes |
A packed sample (samples.pack_id set) is excluded from the public /api/samples listing — it only surfaces through its pack.
All routes require login. See COLLAB.md for the full feature writeup.
| Method | Path | Description |
|---|---|---|
GET |
/api/collab |
List shared projects. mine=true scopes to the caller's own |
GET |
/api/collab/:id |
Project metadata plus its versions and stems |
POST |
/api/collab |
Create a project (requires canPublishContent) |
DELETE |
/api/collab/:id |
Delete a project and its stems (owner only) |
POST |
/api/collab/:id/versions |
Save an append-only version snapshot (state, optional note) |
POST |
/api/collab/:id/stems |
Upload an audio stem (multipart/form-data: file, optional name) |
GET |
/api/collab/:id/stems/:stemId/download |
Stream a stem's audio |
DELETE |
/api/collab/:id/stems/:stemId |
Delete a stem (stem author or project owner) |
| Method | Path | Description |
|---|---|---|
POST |
/api/payments/stripe/create-session |
Create a Stripe Checkout session for fiat purchases |
POST |
/api/payments/stripe/create-trackcap-session |
Create a Stripe Checkout session to buy extra track-upload slots |
GET |
/api/payments/onramp-config |
Stripe Crypto Onramp configuration |
POST |
/api/payments/verify |
Verify an on-chain transaction (ETH/USDC) on Base |
GET |
/api/payments/download/:trackId?code=... |
Download a purchased track via unlock code |
GET |
/api/payments/rate/USD |
Current ETH/USD exchange rate |
| Method | Path | Description |
|---|---|---|
GET |
/api/storage/gdrive/auth |
Start the Google Drive OAuth2 flow |
GET |
/api/storage/gdrive/files |
List files and folders on Google Drive |
POST |
/api/storage/gdrive/import |
Import a Drive file as a gdrive:// reference |
POST |
/api/storage/gdrive/localize/:id |
Permanently download a cloud file to the local server |
| Method | Path | Description |
|---|---|---|
GET |
/api/metadata/search?q=... |
Search album metadata across external providers (MusicBrainz, Discogs, iTunes, TheAudioDB) |
GET |
/api/metadata/lyrics?artist=...&title=... |
Fetch song lyrics via Lyrics.ovh |
POST |
/api/metadata/apply |
Apply selected metadata to a local track |
| Method | Path | Description |
|---|---|---|
GET |
/api/artists/:id/posts |
List an artist's public posts |
POST |
/api/admin/posts |
Create a new post (admin only) |
GET |
/api/comments/track/:trackId |
List comments for a specific track |
POST |
/api/comments/track/:trackId |
Add a comment (requires authentication) |
GET |
/api/ap/timeline/:artistId |
Recent activity from followed actors |
GET |
/api/ap/users/:slug |
ActivityPub profile (actor) for a local user |
POST |
/api/ap/inbox |
Receive incoming remote ActivityPub messages |
POST |
/api/releases/:id/report |
Report a release for copyright or inappropriate content |
GET |
/api/admin/reports |
List all active release reports (admin only) |
DELETE |
/api/admin/reports/:id |
Resolve or dismiss a report (admin only) |
| Method | Path | Description |
|---|---|---|
GET |
/api/admin/system/users |
List registered users (admin only) |
POST |
/api/admin/system/rescan |
Trigger a full library rescan |
POST |
/api/admin/upload/tracks |
Store one or more audio files and scan them into the library (admin/artist only). releaseSlug links them to a release; artist/album name the container. title and trackNum set one track's title and position and are honoured only when a single file is sent — with several files each one keeps its own tags. Used by the release editor to fill an imported tracklist, whose files are rarely tagged the way the release lists them |
POST |
/api/admin/upload/additional-artworks |
Upload multiple additional artworks/booklets for a release (admin/artist only) |
GET |
/api/admin/stats |
Server and database usage statistics |
GET |
/api/admin/system/resources |
Live process/host resource snapshot — CPU, memory, host RAM, SQLite DB size, and running background tasks (root admin only) |
GET |
/api/admin/storage/overview |
Instance-wide disk usage and per-user breakdown (root admin only) |
P2P content acquisition (Soulseek, BitTorrent, yt-dlp) has moved out of the backend into the Sidecamp desktop app; the former
/api/admin/torrents*endpoints no longer exist.
A single always-on station that streams the instance's catalog. Start/stop is admin-only; the stream and feeds are public.
| Method | Path | Description |
|---|---|---|
GET |
/api/radio |
Current station status (playing track, listener count) |
POST |
/api/radio/start |
Start the station (admin only) |
POST |
/api/radio/stop |
Stop the station (admin only) |
GET |
/api/radio/stream.m3u |
M3U playlist for external players |
GET |
/api/radio/feed.rss |
RSS feed of the station |
GET |
/api/radio/hls/:file |
HLS playlist/segments for in-browser playback |
TuneCamp implements the Subsonic protocol (v1.16.1) for compatibility with existing mobile clients such as DSub, Symfonium, Tempo, and Substreamer.
- Base path:
/rest/*.view - Supported methods include:
getAlbumList,getMusicDirectory,stream, and more.
See SUBSONIC.md for the full compatibility table.
TuneCamp implements MCP so that external AI clients can query the catalog and server statistics.
| Method | Path | Description |
|---|---|---|
GET |
/api/mcp/sse |
Open the async SSE channel. Requires Bearer tc_... authentication |
POST |
/api/mcp/message |
Send a JSON-RPC request from client to server |
See mcp-setup-guide.md for client configuration.
All API responses (except audio streams) are JSON. On error, the server returns an appropriate HTTP status code and an error object:
{
"error": "Descriptive error message"
}