AI & automation
API Reference for Agents

Tape Music Hub API Reference for Agents

Current REST + SSE API for automation against the desktop hub.

Defaults

  • Base URL: http://localhost:38472
  • Protocol: REST + SSE
  • Format: JSON
  • Data dir: ~/.music-hub

Port

The installed Desktop app always serves on 38472 — it is not user-configurable from the app UI, so a local agent can hardcode it.

PORT is only configurable for Docker/server deployments, set at container start via the PORT environment variable — the Docker guide itself always uses the 38472 default. An agent targeting a Docker-deployed hub should get the actual port from whoever deployed it (their docker-compose/env config), not assume 38472.

Trust and auth

  • Loopback / same-machine: no auth required, full API access.
  • LAN (same Wi-Fi): most read endpoints open; writes may require pairing or MUSIC_HUB_API_TOKEN.
  • Remote / proxied: requires active license + bearer token from /api/auth/pair or /api/auth/refresh.

Public unauthenticated routes:

  • GET /api/ping, GET /api/info
  • POST /api/auth/pair, POST /api/auth/refresh
  • GET /api/share/:type/:id/bootstrap
  • POST /api/share/session/heartbeat
  • GET /api/collab/invites/preview-opaque, POST /api/collab/invites/claim-opaque

Fast start

# Health + info
curl http://localhost:38472/api/ping
curl http://localhost:38472/api/info

If databaseHealth.status is not healthy, most library routes return 503 database_unavailable.

Pairing flow (for remote agents)

1. Arm pairing window (from the desktop UI)

Open Connections (sidebar) in the desktop app and arm a pairing window. Agents on the same machine can read pairing state directly.

2. Exchange pairing code for tokens

curl -X POST http://localhost:38472/api/auth/pair \
  -H 'Content-Type: application/json' \
  -d '{"pairingCode":"abc123","deviceId":"agent-1","deviceName":"automation"}'

3. Use the access token

curl "http://localhost:38472/api/tracks?limit=5" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

4. Refresh when needed

curl -X POST http://localhost:38472/api/auth/refresh \
  -H 'Content-Type: application/json' \
  -d '{"deviceId":"agent-1","refreshToken":"..."}'

Core read endpoints

Library & Stats

  • GET /api/library/stats — track/album/artist counts, total duration/size, distributions
  • GET /api/library/filters — available genres, tags, formats, BPM range, year range, folders
  • GET /api/tracks?limit=50&offset=0 — paginated tracks with filters (genre, year, BPM, tags, folder, duration, sort)
  • GET /api/tracks?match=query — full-text filter across title, artist, album, genres, tags
  • GET /api/tracks/:id — single track
  • GET /api/tracks/:id/metadata — metadata overlay (genres, tags, enrichment, ISRC, barcode, MBIDs)

Core track fields (GET /api/tracks/:id, and the tracks array from list endpoints):

FieldTypeDescription
idstringUnique track ID
titlestringTrack title
artiststringPrimary artist
albumstringAlbum name
albumArtiststring?Album artist
yearnumber?Release year
genrestring?Genre tag
trackNumbernumber?Track position in album
durationnumberDuration in seconds
bpmnumber?Beats per minute
bitratenumber?Bitrate in kbps
formatstringFile format (mp3, flac, etc.)
filePathstringAbsolute path to file
lastPlayedstring?ISO 8601 timestamp
dateAddedstringISO 8601 timestamp

This is the core field set only. GET /api/tracks/:id/metadata layers additional fields on top (genres[], tags[], enrichment provenance, ISRC, barcode, MBIDs) — call it directly rather than assuming its shape from this table. Albums, artists, playlists and every other resource below do not have a published field table yet: call the endpoint against a running hub and read the live response.

Library structure & folders

  • GET /browse — root level returns the configured source folders (the roots added in Settings > Folders); pass path=<folder> to walk into a folder and see its entries.
  • GET /api/library/filters — includes the distinct folders values actually present across indexed tracks, alongside genres, tags, formats, BPM range and year range. Use this to see what folder structure Tape has indexed today, not just what roots are configured.

There is no vector/embedding index in Tape's database. All metadata is relational (title, artist, album, genre, BPM, tags, enrichment fields, etc.) — reason over those structured fields, not over similarity vectors.

There is currently no endpoint to move or rename files on disk. Folder/file reorganization stays host-only; an agent can read structure and metadata and propose field-level metadata changes (see Core write endpoints), but not trigger a physical reorganization yet.

Albums, Artists, Labels

  • GET /api/albums?limit=50&offset=0
  • GET /api/albums/:id, GET /api/albums/:id/tracks
  • GET /api/artists?limit=50&offset=0
  • GET /api/artists/:id, GET /api/artists/:id/tracks, GET /api/artists/:id/albums
  • GET /api/labels?limit=50&offset=0, GET /api/labels/:id

Playlists

  • GET /api/playlists
  • GET /api/playlists/:id, GET /api/playlists/:id/tracks
  • POST /api/playlists { "name": "...", "description": "...", "folder": "..." }
  • POST /api/playlists/:id/tracks { "trackIds": [...] }
  • DELETE /api/playlists/:id

Search

  • GET /api/search?q=miles+davis&type=tracks|albums|artists&limit=50

Playback & History

  • GET /api/playback/state — current queue state
  • GET /api/library/recently-played?limit=10
  • GET /api/analytics/play-history?days=7&limit=100 — chronological play events
  • GET /api/analytics/hub-counter — global playback counter + license gate

Agent Playback

  • POST /api/agent/play — start playback from agent context
    { "trackIds": ["abc123"], "startIndex": 0 }
  • POST /api/agent/queue — add tracks to current queue without interrupting
    { "trackIds": ["ghi789"] }

Shared / Saved

  • GET /api/saved — saved track/artist/album IDs
  • GET /api/library/bookmarked — bookmarked playlists
  • GET /api/share/:type/:id/bootstrap — public share page data

AI Context

  • GET /api/ai/context — current track, queue, session snapshot

Core write endpoints

  • PUT /api/saved/tracks/:id { "status": "new|saved|heard", "source": "desktop|mobile" }
  • POST /api/play/events { "trackId": "...", "source": "desktop|mobile", "completed": true }
  • PUT /api/tracks/:id/metadata/curated { "genres": [...], "tags": [...], "styles": [...] }
  • PUT /api/tracks/:id/metadata/overrides { "manualGenres": [...], "manualTags": [...] }
  • DELETE /api/tracks/:id/metadata/overrides
  • POST /api/tracks/:id/tags/write-to-file
  • PUT /api/tracks/:id/primary-metadata { "title": "...", "artist": "...", "album": "..." }

Enrichment

  • GET /api/tracks/:id/enrichment/job — current enrichment status
  • POST /api/tracks/:id/re-enrich/search { "provider": "musicbrainz|discogs", "title": "...", "artist": "...", "album": "..." }
  • POST /api/tracks/:id/re-enrich/apply { "provider": "musicbrainz", "candidate": {...} }

License

  • POST /api/license/activate { "licenseKey": "..." }
  • POST /api/license/validate { "force": true }
  • GET /api/license/status

Inbox / Library triage

  • POST /api/library/inbox/remove { "trackIds": [...] }
  • POST /api/library/inbox/clear
  • POST /api/library/inbox/mark-heard { "trackIds": [...] }
  • POST /api/library/inbox/mark-to-listen { "trackIds": [...] }
  • POST /api/library/inbox/undo

SSE feeds

  • GET /api/library/events — track updates, enrichment status, metadata changes
  • GET /api/events/stream — scan progress, track added/updated/deleted

Remote / Tunnel

  • GET /api/remote/status
  • POST /api/remote/cloudflare/setup, POST /api/remote/cloudflare/delete
  • POST /api/remote/route/toggle { "route": "cloudflare|sovereign", "enabled": true }

Legacy Tailscale setup endpoints may still exist in older builds; they are not part of the 0.3.0 Settings product path. Prefer Personal Private Network (Iroh/sovereign) + optional Cloudflare.

Diagnostics

  • GET /api/diagnostics/status
  • POST /api/diagnostics/upload

Settings

  • GET /api/settings
  • PUT /api/settings/server { "name": "...", "port": 38472 }

Local-only operations

These must run on the desktop host itself (loopback):

  • POST /api/settings/folders/rescan
  • POST /api/database/rebuild
  • GET /api/auth/devices, DELETE /api/auth/devices/:deviceId
  • GET /api/analytics/hub-counter/recalculate

Share-specific public routes

  • GET /api/share/playlist/:id/bootstrap
  • GET /api/share/artist/:id/bootstrap
  • GET /api/share/album/:id/bootstrap
  • GET /api/share/track/:id/bootstrap
  • POST /api/share/session/heartbeat

Bootstrap responses include shareSessionId and mediaToken. Both are short-lived.

Recovery

If the hub reports a faulted database:

curl http://localhost:38472/api/info
# Check databaseHealth.status
curl -X POST http://localhost:38472/api/database/rebuild

Do not script destructive DB deletion. The hub preserves and archives faulted DBs.

Failure modes

  • 401 — remote auth missing or expired
  • 403 — license required or local-only endpoint called remotely
  • 404 — resource not found
  • 409 pairing_not_armed — pairing window not active
  • 503 database_unavailable — hub DB is faulted or incompatible

Full reference

See the complete markdown doc shipped with the desktop app: desktop/docs/API-REFERENCE-FOR-AGENTS.md

Keeping this reference accurate

This page is hand-written prose, not generated from an OpenAPI/JSON Schema spec — it can drift from desktop/src/core/api/routes/*.ts the same way the old "Suggestions" section did (documented /api/suggestions and /api/tracks/:id/similar, neither of which had a matching route). Follow this pattern when routes change:

  1. Only document what exists. A route must already be implemented in desktop/src/core/api/routes/*.ts before it's added here or to desktop/docs/API-REFERENCE-FOR-AGENTS.md or Integration Guide. Planned/future endpoints belong in working/roadmap/ or working/tasks/, never in agent-facing docs — that's how this page and working/API-REFERENCE-FOR-AGENTS.md ended up describing a /mcp server and /api/ai/suggest//api/ai/patterns that were never built.
  2. Update in the same change. A PR that adds, renames or removes a route under desktop/src/core/api/routes/ updates this page (and integration.mdx when it affects an agent workflow) in that same change, not as a follow-up.
  3. Audit periodically. List the routes actually mounted and diff by eye against what's documented here:
    grep -rhoE "router\.(get|post|put|delete)\('[^']+'" desktop/src/core/api/routes/*.ts | sort -u
    Anything in that output missing from this page, or documented here with no matching route, is the audit finding.