Metadata
This guide covers all metadata available through the Partner API: what fields are returned, how to fetch metadata efficiently, and what limitations exist.
Track metadata fields
All track-returning endpoints include a standard set of metadata fields:
| Field | Type | Description |
|---|---|---|
id | string | UUID identifier for the track |
title | string | Track title |
mainArtists | array of strings | Primary artists (never null, but can be empty) |
featuredArtists | array of strings | Featured/guest artists (nullable) |
bpm | number | Beats per minute (integer, never null) |
length | number | Track duration in seconds |
moods | array | Applied mood tags (e.g. ["happy", "energetic"]) |
genres | array | Applied genre tags (e.g. ["pop", "indie-pop"]) |
images | object | Cover art URLs in multiple sizes |
waveformUrl | string | URL to JSON waveform data |
hasVocals | boolean | Whether the track contains any vocal content |
vocalType | string | Vocal classification: LEAD, PRESENCE, or NONE |
isExplicit | boolean | Whether the track contains explicit content |
isPreviewOnly | boolean | Stream-only restriction (see content access) |
tierOption | string | Subscription tier requirement |
isrc | string | International Standard Recording Code (nullable) |
added | string | ISO 8601 timestamp when track was added to catalog |
A note on isPreviewOnly
When true, the track can only be streamed for preview and not downloaded. This depends on the user's subscription status and your partnership agreement.
Known issue: Partners with full catalogue access may see isPreviewOnly: true on tracks discovered outside their collections (e.g. via search, similar tracks, or mood/genre browsing), even though these tracks are actually downloadable. Do not rely on this flag alone to determine download eligibility — attempt the download regardless. See the Fundamentals on content access for details.
Filtering on vocals and explicit content
To narrow a result set on vocals or explicit content:
- Vocals: use
vocalType=NONEon browse or search for instrumental-only results. The filter runs server-side, so your page sizes andlinks.nextstay correct. - Explicit content: music has no server-side filter, so use
isExplicitto flag or hide tracks in your own UI and expect page sizes to vary. Sound effects do have one — seeincludeExplicit.
How to fetch metadata
Inline with content endpoints
Metadata comes automatically with every track-returning endpoint:
/v0/tracks(browse)/v0/tracks/search/v0/tracks/{id}/similar/v0/collections/{id}(collection tracks)/v0/genres/{id}(genre tracks)/v0/moods/{id}(mood tracks)
ISRC lookup: These endpoints also accept ISRCs directly as track IDs (e.g., GET /v0/tracks/metadata?trackId=SE5Q52304763). An empty array response is a definitive "not in catalog" result.
Batch metadata lookup
Use /v0/tracks/metadata for efficient batch metadata retrieval:
GET /v0/tracks/metadata?trackId=uuid1&trackId=uuid2&trackId=uuid3
Batch size limit: The endpoint accepts multiple trackId parameters in the URL, but HTTP request line limits cap you at roughly 90 track IDs per request (4096-byte limit). For larger lists, split into batches and make parallel requests.
Single track metadata
Use /v0/tracks/{id} to get metadata for one specific track.
Taxonomies
Moods and genres
Moods (46 total): Emotional/atmospheric descriptors like happy, epic, relaxing. Full list retrieved via /v0/moods.
Genres (~500 total): Musical style tags with parent-child relationships. Parent genres (e.g. rock) match tracks tagged with any child genre (indie-rock, alternative-rock). Retrieved via /v0/genres.
Both endpoints:
- Default to
type=all(full catalog) - Support
type=featuredfor curated subsets - Are capped at 20 results per page - paginate for complete lists
- Include parent/child relationships in the response
Vocal types
NONE: Fully instrumentalPRESENCE: Vocal chops, samples, ad-libs, textures (no lead vocal)LEAD: Sung lead vocals
Combined parameters endpoint
Use /v0/tracks/parameters to get moods and genres in one response - useful for building LLM enum schemas (providing AI models with valid option lists) or search UIs.
Facet counts (aggregations)
Search results include an aggregations object with facet counts:
{
"aggregations": {
"genres": [
{ "id": "pop", "name": "pop", "count": 45 },
{ "id": "indie-pop", "name": "indie-pop", "count": 23 }
],
"moods": [
{ "id": "happy", "name": "happy", "count": 67 },
{ "id": "energetic", "name": "energetic", "count": 34 }
]
}
}
Important caveats:
- Search-only: Only
/v0/tracks/searchpopulates aggregations. Browse and other endpoints return"aggregations": null. Sincetermis optional on search, you can still get facet counts for a filter-only request — see Browse vs. Search. - Exact co-occurrence: Counts reflect how many tracks in the current result set have each tag, not catalog totals.
- Top 20 cap: Each dimension (moods, genres) returns only the 20 most common tags in the result set.
nameis a slug, not a label: Unlike everywhere else in the API, thenameinsideaggregationsrepeats theidinstead of giving a display label — you getlaid-backandhip-hop, where/v0/moodsand/v0/genresreturnLaid BackandHip Hop. Don't render it directly; resolve it instead, as below.
Labelling facets
Build an id-to-name map from /v0/moods and /v0/genres, which do return display labels. Every aggregation id resolves against them.
Fetch this once and cache it rather than per search: both endpoints cap limit at 20, so the full taxonomy is 3 requests for the 46 moods and around 28 for the ~540 genres. The lists change rarely.
// Built once at startup from the paginated /v0/genres response
const genreNames = new Map(allGenres.map((g) => [g.id, g.name]))
const facets = response.aggregations.genres.map((g) => ({
id: g.id,
label: genreNames.get(g.id) ?? g.id, // "hip-hop" -> "Hip Hop"
count: g.count,
}))
If you only need labels for a handful of featured values, type=featured returns 12 moods and 12 genres in a single call each.
Sound effect metadata
Sound effects include the following metadata fields:
| Field | Type | Description |
|---|---|---|
id | string | UUID identifier |
title | string | Effect title — a comma-separated taxonomy path, general to specific, e.g. Footsteps, Human, Gravel, Walk. See how titles are structured |
length | number | Duration in seconds |
added | string | ISO 8601 timestamp |
images | object | URLs to cover art in multiple sizes (usually category artwork) |
That is the complete set — sound effects carry no BPM, moods, genres or tags. Client-side filtering of results is therefore limited to title and length; everything else has to come from the search and category endpoints.
Unlike music, sound effects do have a server-side explicit filter: includeExplicit defaults to false on both search and category tracks.