Catalogue search
Structured catalogue search with POST /v1/search/tracks.
Use catalogue search to find tracks across accessible Workspace catalogues
and, when entitled, MusiMap Atlas. The public endpoint is
POST /v1/search/tracks. Criteria are explicit: title and artist text, taxonomy
tags, identifiers, and audio-feature ranges.
POST /v1/search/tracks searches analysed catalogue content with explicit
text and structured filters.
GET /v1/workspace/tracks and GET /v1/atlas/tracks list technical
inventory. Use inventory for browse, exact IDs, and delivery metadata. Use catalogue
search to select tracks by title, artist, tag IDs, and audio attributes, then retrieve
a selected entity from its plane inventory endpoint when you need the full record.
Use Catalogue Search when you have explicit criteria: lexical title and artist
terms, taxonomy tags, identifiers, or supported audio-feature filters.
query is lexical, not natural language. After Unicode case-folding and collapsed
whitespace, every term must appear as a whole token in the track title or the
primary artist credit. Terms may be split across those fields and do not need
to be adjacent. If any query term is missing from both fields, the track does
not match. Catalogue Search does not interpret moods, styles, context, intent,
or prose.
MusiSearch is MusiMap's natural-language music discovery capability.
It is intended for descriptions that involve moods, styles, context, intent,
or prose. See
Discovery
(POST /v1/discovery). Catalogue Search remains the public API for
explicit, structured criteria.
OAuth scopes
- search.read: run structured catalogue search.
- atlas.read: required when
include_atlasis true ortargetsincludesatlas(plus matching organisation entitlement).
Tag IDs
Tag filters use stable tag IDs from
GET /v1/tagging/taxonomy
(categories[].tags[].id). Pass those values as tag_id in filters.
Tag labels are display metadata only.
Workspace and Atlas inclusion
include_workspace: include organisation Workspace catalogues.include_atlas: include MusiMap Atlas (requiresatlas.read).targets: alternative array ofworkspaceand/oratlas.catalog_id/catalog_ids: optional Workspace catalogue overrides.
Each hit includes source.layer: workspace or atlas.
When you need the full inventory record, retrieve it from
GET /v1/workspace/tracks/{id} or
GET /v1/atlas/tracks/{id} accordingly.
Atlas and Workspace inventory are also browsable directly without searching first.
See Atlas.
Search request
Provide at least one of query, filters or an explicit sort other than score. A sort on its own orders every accessible track: for example {"sort": "bpm", "sort_direction": "asc"} returns the slowest tracks first.
curl -X POST "https://api.musimap.com/v1/search/tracks" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "Fever Dua Lipa",
"catalog_id": "0190…",
"include_workspace": true,
"include_atlas": true,
"filters": {
"tags": {
"required": [
{ "tag_id": "0190…", "score_min": 70, "score_max": 100 }
],
"optional": [
{ "tag_id": "0190…", "score_min": 50 }
],
"excluded": [
{ "tag_id": "0190…", "score_min": 60 }
]
},
"bpm_min": 100,
"bpm_max": 140
},
"sort": "score",
"sort_direction": "desc",
"page": 1,
"page_size": 20
}'
Text matching
query is required eligibility when present. After Unicode case-folding
and collapsed whitespace, every term must appear as a whole token in the track title,
the primary artist credit, or both. Terms do not need to sit in the same field or next
to one another, so Fever Dua Lipa matches title
Fever and artist Dua Lipa.
Combine it with BPM, tags, or identifiers using AND: every required
condition must hold. Additional title/artist filters
(title_contains, title_exact, artist_contains,
artist_exact) are also AND constraints.
Tag filter modes
required: eligibility. The track must match every required condition.optional: preference. Eligible tracks remain in the result; optional matches changesearch.score.excluded: exclude tracks where the tag score falls within the range.
Other supported filters
isrc,outer_id.bpm_min,bpm_max,energy_min,energy_max.title_contains,title_exact,artist_contains,artist_exact.
artist_exact matches a primary artist name exactly as returned in
artists[].name on search hits (case-sensitive as stored). On multi-artist
tracks, any credited primary artist name may match. Do not treat joined credit
strings as a separator protocol for artist names.
artist_contains is a case-insensitive substring match on the stored primary
artist credit text used for lexical search.
Use taxonomy tag id values (as tag_id in filters) rather than label lists such as
genres or moods. Unknown filter names are rejected.
Preference score
search.score is a value from 0 to 100. Required criteria
decide whether a track is returned at all. When there are no optional tag or numeric
preferences, every eligible result scores 100. With optional preferences,
the score is the share of the available optional weight that the track actually earned
(clamped to 0–100). A score of 0 with optional preferences means none of
those preferences matched; the track is still eligible.
Sort and pagination
Default order is score descending; among equal scores, Workspace hits come before
Atlas hits, then immutable track_id ascending. track_id ascending compares
identifiers in their canonical text form; these identifiers are time-ordered, so this approximates
creation order, but it is not an ingestion timestamp. The same tie-breaks follow every other
sort or sorts key, and sort=track_id uses the same canonical
order. The same request over unchanged data returns the same order on every page; tracks ingested
or reanalysed between two requests can shift later pages. Supported sort values: score, track_id,
title, artist, bpm, updated_at.
relevance is a compatibility alias for score.
Optional sort_direction is asc or desc.
updated_at is the analysis projection timestamp and can move while ingest
is active. Pagination is over logical tracks after collapsing multiple analyses per
track, not an unordered sample.
Sorting by several keys
sorts is an ordered list of up to five keys, applied lexicographically over every eligible
track: the first key orders all results, each further key only orders the tracks tied on the previous
keys. Each key is {"field", "direction"}; field accepts the sort
values above, the audio features energy, danceability,
loudness_lufs, instrumental_probability and release_year, and
tag_score, which orders by one tag's score and requires its tag_id.
Tracks without a value for a key come last for that key. Sorting never changes which tracks are eligible
or their preference score. Use either sorts or sort/sort_direction,
not both; an unsupported field or key is rejected with 400 validation_error.
{
"include_atlas": true,
"sorts": [
{ "field": "tag_score", "tag_id": "<Happy tag_id>", "direction": "desc" },
{ "field": "bpm", "direction": "asc" }
]
}
This lists the happiest tracks first; among tracks with the same Happy score, the slowest come first.
Response shape
{
"status": 200,
"message": "OK",
"data": {
"count": 1,
"page": 1,
"page_size": 20,
"total_pages": 1,
"has_next": false,
"has_previous": false,
"results": [
{
"track": {
"id": "0190…",
"title": "Fever",
"outer_id": "client-track-42"
},
"artists": [{ "id": "0190…", "name": "Dua Lipa" }],
"release": { "id": "0190…", "title": "Future Nostalgia" },
"source": { "layer": "workspace", "catalog_id": "0190…" },
"audio_tagging": {
"taxonomy_version": "v1",
"tags": {
"moods": [{ "uid": "mood_happy", "name": "Happy", "score": 82 }]
}
},
"search": { "score": 100 }
}
]
}
}
Need natural-language discovery?
For moods, styles, context, and prose queries, use Discovery (MusiSearch).