Skip to content

A master (release-group) dossier, addressed under its artist

GET
/api/v2/artist/{key}/master/{id}
curl --request GET \
--url https://crate.hosaka.fm/api/v2/artist/example/master/example \
--header 'X-API-Key: <X-API-Key>'

Cycle-091 — the full per-master dossier (header, every signal section, artwork, provenance — the rich MasterDossierContract the master grain has always produced), addressed cluster-first UNDER the artist. {key} = 64-hex cluster_id (canonical) or slug; {id} = discogs_master_id (list them via the artist dossier’s discography facet). CLUSTER-FIRST INTEGRITY: the master must be filed under the addressed artist AND authoritatively bound (not via a homonym name over-merge) — otherwise 200 present:false honest-gap, never another artist’s master. When bound via an over-merged name cluster, binding.observed=true flags it OBSERVED/UNVERIFIED (mirrors the discography facet). Keyed (X-API-Key); malformed id → 400; unresolved/mismatch → 200 present:false, NOT 404. NOTE: the Discogs collector count (owner_count) is intentionally absent — retired as an anti-signal in cycle-082, not lost in the cluster cut.

key
required
string
>= 1 characters <= 200 characters
id
required
string
/^\d{1,9}$/

The master dossier (present:true) or an honest-gap (present:false — unknown, or not filed under this artist)

Media type application/json
Any of:
object
object
required
string
Allowed values: master.dossier
present
required
boolean
binding
required
object
observed
required
boolean
master
required
object
contract_version
required
string
grain
required
string
Allowed values: master
id
required
number
header
required
object
title
required
string
artist
required
string | null
year
required
number | null
formats
required
Array<string>
cube_quadrant
required
object
code
required
string | null
label
required
string | null
sections
required
Array<object>
object
field
required
string
state
required
string
artwork
required
Array<object>
object
url
required

Hotlink-only artwork URL: a Bandcamp CDN string, or a deterministic Cover Art Archive release-group URL. crate never fetches or re-hosts the bytes; a CAA url is best-effort and may 404 if no cover exists.

string
source
required
string
Allowed values: bandcamp coverartarchive
grain
required
string
Allowed values: artist release
license
required
string
rehost
required

A const literal — always the boolean false — declaring crate’s link-only artwork posture. WHY IT MATTERS: it is a contractual promise that the url on the artwork item is a HOTLINK the caller dereferences directly (a Bandcamp CDN url or a deterministic Cover Art Archive url); crate never fetches, caches, or re-hosts the image bytes. GOTCHA: because crate never dereferences the url, it can be stale or 404 (a CAA url is best-effort and may not exist) — your client must handle a broken image gracefully. Treat rehost:false as a fixed flag, not a toggle; it will never be true.

boolean
width

Delivered pixel width of the hotlinked image. For bandcamp these are the _16 locator’s render dims (700×700 square) — exactly the box the hotlink renders at, NOT the original artwork’s source aspect (HEAD the url for non-square edge cases). Absent when the source carries no dims (coverartarchive).

integer
height

Delivered pixel height — see width.

integer
freshness
required
object
mirror_lag_s
required
number | null
seen_lag_s
required
number | null
cache
required
object
etag
required
string
maxAge
required
number
provenance
required
Array
generated_at
required
string
Example
{
"object": "master.dossier",
"present": true,
"master": {
"grain": "master",
"artwork": [
{
"source": "bandcamp",
"grain": "artist",
"rehost": false
}
]
}
}
X-RateLimit-Limit
integer

Requests allowed in the current window.

X-RateLimit-Remaining
integer

Requests remaining in the current window.

X-RateLimit-Reset
integer

Unix epoch (seconds) when the current window resets.

Validation failure (invalid query, malformed body, bad facet name)

Media type application/json

The error envelope for all 4xx/5xx responses. error is the only guaranteed field — branch on it, never on HTTP status alone. An unresolved/empty lookup is NOT an error: it returns HTTP 200 with present:false / a null field / state:"honest_gap".

codeHTTPwhen thrownfix
invalid_artist_key400/artist/{key} key is not a 64-hex cluster_id, discogs:<id>, or mbid:<uuid>resolve by name first: GET /api/v2/resolve?q=<name>, then call /artist/{cluster_id}
use_resolve_for_locator400/artist/{key} given a discogs:/mbid: locator (not a canonical address)GET /api/v2/resolve?discogs=<id> (or ?mbid=), then use the returned cluster_id (the response next field is the ready-to-call URL)
invalid_label_key400/label/{key} key is not a 64-hex label_cluster_id or name-slug (e.g. a discogs:/mbid: locator — not resolvable for labels yet)address a label by its 64-hex label_cluster_id or its name-slug (e.g. /api/v2/label/warp)
invalid_fields400/artist/{key}?fields= lists a facet that is not a valid top-level dossier fielduse only the fields in the response valid set; omit ?fields= entirely for the full dossier (see the example field)
missing_locator400/resolve called with none of q/cluster/discogs/mbidpass exactly one locator
invalid_locator400a /resolve locator is malformed for its typefix the format, or fall back to ?q=<name>
invalid_query400/search ?q= missing/empty, or any Zod validation failure (details[] attached)pass ?q=<text>; fix each details entry
invalid_facet400an unknown facet filter name was suppliedGET /api/v2/facets for valid names + values
rate_limited429an IP/key/tier rate or concurrency cap was exceeded (retry_after_seconds + Retry-After + X-RateLimit-* set)back off retry_after_seconds (or until X-RateLimit-Reset), then retry
object
error
required

Machine-readable error code (stable lowercase snake_case). The ONLY field guaranteed on every error body — switch on it programmatically, never on HTTP status alone (several codes share a status). See the code table in this schema’s description.

string
message

One-sentence human-readable statement of WHAT is wrong (developer-facing). Present only for catalogued codes. Describes the violated rule — not a fix (see hint/next).

string
hint

Actionable remediation in human terms — what to DO next, often naming the exact endpoint (a template with ). The human counterpart to the machine-actionable next.

string
doc_url

Deep link to this code’s docs: https://crate.hosaka.fm/docs/api#error-. Auto-populated for catalogued codes.

string
param

The specific request parameter that caused the failure (e.g. “key”, “q”), so a client can point at the offending input. Present only when the code declares one.

string
next

A copy-pasteable, fully-formed corrected call (a concrete URL, NOT a template) an agent can fire verbatim to recover — the machine-actionable counterpart to hint. Present only when a handler supplies one.

string
details

Structured validation breakdown — on Zod 400s (invalid_query), an array of { path, message }, one per failed field. Present only when validation specifics are attached.

Array
retry_after_seconds

On a 429 rate_limited response, seconds to wait before retrying (mirrors the Retry-After header). Sleep at least this long, then re-issue the identical request.

number
master_id

Echoed on master_not_found (404) — the master id that did not resolve.

number
Example
{
"error": "invalid_query"
}

Authentication failure

Media type application/json

The error envelope for all 4xx/5xx responses. error is the only guaranteed field — branch on it, never on HTTP status alone. An unresolved/empty lookup is NOT an error: it returns HTTP 200 with present:false / a null field / state:"honest_gap".

codeHTTPwhen thrownfix
invalid_artist_key400/artist/{key} key is not a 64-hex cluster_id, discogs:<id>, or mbid:<uuid>resolve by name first: GET /api/v2/resolve?q=<name>, then call /artist/{cluster_id}
use_resolve_for_locator400/artist/{key} given a discogs:/mbid: locator (not a canonical address)GET /api/v2/resolve?discogs=<id> (or ?mbid=), then use the returned cluster_id (the response next field is the ready-to-call URL)
invalid_label_key400/label/{key} key is not a 64-hex label_cluster_id or name-slug (e.g. a discogs:/mbid: locator — not resolvable for labels yet)address a label by its 64-hex label_cluster_id or its name-slug (e.g. /api/v2/label/warp)
invalid_fields400/artist/{key}?fields= lists a facet that is not a valid top-level dossier fielduse only the fields in the response valid set; omit ?fields= entirely for the full dossier (see the example field)
missing_locator400/resolve called with none of q/cluster/discogs/mbidpass exactly one locator
invalid_locator400a /resolve locator is malformed for its typefix the format, or fall back to ?q=<name>
invalid_query400/search ?q= missing/empty, or any Zod validation failure (details[] attached)pass ?q=<text>; fix each details entry
invalid_facet400an unknown facet filter name was suppliedGET /api/v2/facets for valid names + values
rate_limited429an IP/key/tier rate or concurrency cap was exceeded (retry_after_seconds + Retry-After + X-RateLimit-* set)back off retry_after_seconds (or until X-RateLimit-Reset), then retry
object
error
required

Machine-readable error code (stable lowercase snake_case). The ONLY field guaranteed on every error body — switch on it programmatically, never on HTTP status alone (several codes share a status). See the code table in this schema’s description.

string
message

One-sentence human-readable statement of WHAT is wrong (developer-facing). Present only for catalogued codes. Describes the violated rule — not a fix (see hint/next).

string
hint

Actionable remediation in human terms — what to DO next, often naming the exact endpoint (a template with ). The human counterpart to the machine-actionable next.

string
doc_url

Deep link to this code’s docs: https://crate.hosaka.fm/docs/api#error-. Auto-populated for catalogued codes.

string
param

The specific request parameter that caused the failure (e.g. “key”, “q”), so a client can point at the offending input. Present only when the code declares one.

string
next

A copy-pasteable, fully-formed corrected call (a concrete URL, NOT a template) an agent can fire verbatim to recover — the machine-actionable counterpart to hint. Present only when a handler supplies one.

string
details

Structured validation breakdown — on Zod 400s (invalid_query), an array of { path, message }, one per failed field. Present only when validation specifics are attached.

Array
retry_after_seconds

On a 429 rate_limited response, seconds to wait before retrying (mirrors the Retry-After header). Sleep at least this long, then re-issue the identical request.

number
master_id

Echoed on master_not_found (404) — the master id that did not resolve.

number
Example
{
"error": "invalid_query"
}

Rate limit exceeded — see Retry-After + X-RateLimit-* headers

Media type application/json
object
error
required
string
Allowed values: rate_limited
retry_after_seconds
required
number
Example
{
"error": "rate_limited"
}

Internal server error

Media type application/json

The error envelope for all 4xx/5xx responses. error is the only guaranteed field — branch on it, never on HTTP status alone. An unresolved/empty lookup is NOT an error: it returns HTTP 200 with present:false / a null field / state:"honest_gap".

codeHTTPwhen thrownfix
invalid_artist_key400/artist/{key} key is not a 64-hex cluster_id, discogs:<id>, or mbid:<uuid>resolve by name first: GET /api/v2/resolve?q=<name>, then call /artist/{cluster_id}
use_resolve_for_locator400/artist/{key} given a discogs:/mbid: locator (not a canonical address)GET /api/v2/resolve?discogs=<id> (or ?mbid=), then use the returned cluster_id (the response next field is the ready-to-call URL)
invalid_label_key400/label/{key} key is not a 64-hex label_cluster_id or name-slug (e.g. a discogs:/mbid: locator — not resolvable for labels yet)address a label by its 64-hex label_cluster_id or its name-slug (e.g. /api/v2/label/warp)
invalid_fields400/artist/{key}?fields= lists a facet that is not a valid top-level dossier fielduse only the fields in the response valid set; omit ?fields= entirely for the full dossier (see the example field)
missing_locator400/resolve called with none of q/cluster/discogs/mbidpass exactly one locator
invalid_locator400a /resolve locator is malformed for its typefix the format, or fall back to ?q=<name>
invalid_query400/search ?q= missing/empty, or any Zod validation failure (details[] attached)pass ?q=<text>; fix each details entry
invalid_facet400an unknown facet filter name was suppliedGET /api/v2/facets for valid names + values
rate_limited429an IP/key/tier rate or concurrency cap was exceeded (retry_after_seconds + Retry-After + X-RateLimit-* set)back off retry_after_seconds (or until X-RateLimit-Reset), then retry
object
error
required

Machine-readable error code (stable lowercase snake_case). The ONLY field guaranteed on every error body — switch on it programmatically, never on HTTP status alone (several codes share a status). See the code table in this schema’s description.

string
message

One-sentence human-readable statement of WHAT is wrong (developer-facing). Present only for catalogued codes. Describes the violated rule — not a fix (see hint/next).

string
hint

Actionable remediation in human terms — what to DO next, often naming the exact endpoint (a template with ). The human counterpart to the machine-actionable next.

string
doc_url

Deep link to this code’s docs: https://crate.hosaka.fm/docs/api#error-. Auto-populated for catalogued codes.

string
param

The specific request parameter that caused the failure (e.g. “key”, “q”), so a client can point at the offending input. Present only when the code declares one.

string
next

A copy-pasteable, fully-formed corrected call (a concrete URL, NOT a template) an agent can fire verbatim to recover — the machine-actionable counterpart to hint. Present only when a handler supplies one.

string
details

Structured validation breakdown — on Zod 400s (invalid_query), an array of { path, message }, one per failed field. Present only when validation specifics are attached.

Array
retry_after_seconds

On a 429 rate_limited response, seconds to wait before retrying (mirrors the Retry-After header). Sleep at least this long, then re-issue the identical request.

number
master_id

Echoed on master_not_found (404) — the master id that did not resolve.

number
Example
{
"error": "invalid_query"
}

Database pool exhausted — retry after 5s

Media type application/json

The error envelope for all 4xx/5xx responses. error is the only guaranteed field — branch on it, never on HTTP status alone. An unresolved/empty lookup is NOT an error: it returns HTTP 200 with present:false / a null field / state:"honest_gap".

codeHTTPwhen thrownfix
invalid_artist_key400/artist/{key} key is not a 64-hex cluster_id, discogs:<id>, or mbid:<uuid>resolve by name first: GET /api/v2/resolve?q=<name>, then call /artist/{cluster_id}
use_resolve_for_locator400/artist/{key} given a discogs:/mbid: locator (not a canonical address)GET /api/v2/resolve?discogs=<id> (or ?mbid=), then use the returned cluster_id (the response next field is the ready-to-call URL)
invalid_label_key400/label/{key} key is not a 64-hex label_cluster_id or name-slug (e.g. a discogs:/mbid: locator — not resolvable for labels yet)address a label by its 64-hex label_cluster_id or its name-slug (e.g. /api/v2/label/warp)
invalid_fields400/artist/{key}?fields= lists a facet that is not a valid top-level dossier fielduse only the fields in the response valid set; omit ?fields= entirely for the full dossier (see the example field)
missing_locator400/resolve called with none of q/cluster/discogs/mbidpass exactly one locator
invalid_locator400a /resolve locator is malformed for its typefix the format, or fall back to ?q=<name>
invalid_query400/search ?q= missing/empty, or any Zod validation failure (details[] attached)pass ?q=<text>; fix each details entry
invalid_facet400an unknown facet filter name was suppliedGET /api/v2/facets for valid names + values
rate_limited429an IP/key/tier rate or concurrency cap was exceeded (retry_after_seconds + Retry-After + X-RateLimit-* set)back off retry_after_seconds (or until X-RateLimit-Reset), then retry
object
error
required

Machine-readable error code (stable lowercase snake_case). The ONLY field guaranteed on every error body — switch on it programmatically, never on HTTP status alone (several codes share a status). See the code table in this schema’s description.

string
message

One-sentence human-readable statement of WHAT is wrong (developer-facing). Present only for catalogued codes. Describes the violated rule — not a fix (see hint/next).

string
hint

Actionable remediation in human terms — what to DO next, often naming the exact endpoint (a template with ). The human counterpart to the machine-actionable next.

string
doc_url

Deep link to this code’s docs: https://crate.hosaka.fm/docs/api#error-. Auto-populated for catalogued codes.

string
param

The specific request parameter that caused the failure (e.g. “key”, “q”), so a client can point at the offending input. Present only when the code declares one.

string
next

A copy-pasteable, fully-formed corrected call (a concrete URL, NOT a template) an agent can fire verbatim to recover — the machine-actionable counterpart to hint. Present only when a handler supplies one.

string
details

Structured validation breakdown — on Zod 400s (invalid_query), an array of { path, message }, one per failed field. Present only when validation specifics are attached.

Array
retry_after_seconds

On a 429 rate_limited response, seconds to wait before retrying (mirrors the Retry-After header). Sleep at least this long, then re-issue the identical request.

number
master_id

Echoed on master_not_found (404) — the master id that did not resolve.

number
Example
{
"error": "invalid_query"
}

Request deadline (15s) or query timeout exceeded

Media type application/json

The error envelope for all 4xx/5xx responses. error is the only guaranteed field — branch on it, never on HTTP status alone. An unresolved/empty lookup is NOT an error: it returns HTTP 200 with present:false / a null field / state:"honest_gap".

codeHTTPwhen thrownfix
invalid_artist_key400/artist/{key} key is not a 64-hex cluster_id, discogs:<id>, or mbid:<uuid>resolve by name first: GET /api/v2/resolve?q=<name>, then call /artist/{cluster_id}
use_resolve_for_locator400/artist/{key} given a discogs:/mbid: locator (not a canonical address)GET /api/v2/resolve?discogs=<id> (or ?mbid=), then use the returned cluster_id (the response next field is the ready-to-call URL)
invalid_label_key400/label/{key} key is not a 64-hex label_cluster_id or name-slug (e.g. a discogs:/mbid: locator — not resolvable for labels yet)address a label by its 64-hex label_cluster_id or its name-slug (e.g. /api/v2/label/warp)
invalid_fields400/artist/{key}?fields= lists a facet that is not a valid top-level dossier fielduse only the fields in the response valid set; omit ?fields= entirely for the full dossier (see the example field)
missing_locator400/resolve called with none of q/cluster/discogs/mbidpass exactly one locator
invalid_locator400a /resolve locator is malformed for its typefix the format, or fall back to ?q=<name>
invalid_query400/search ?q= missing/empty, or any Zod validation failure (details[] attached)pass ?q=<text>; fix each details entry
invalid_facet400an unknown facet filter name was suppliedGET /api/v2/facets for valid names + values
rate_limited429an IP/key/tier rate or concurrency cap was exceeded (retry_after_seconds + Retry-After + X-RateLimit-* set)back off retry_after_seconds (or until X-RateLimit-Reset), then retry
object
error
required

Machine-readable error code (stable lowercase snake_case). The ONLY field guaranteed on every error body — switch on it programmatically, never on HTTP status alone (several codes share a status). See the code table in this schema’s description.

string
message

One-sentence human-readable statement of WHAT is wrong (developer-facing). Present only for catalogued codes. Describes the violated rule — not a fix (see hint/next).

string
hint

Actionable remediation in human terms — what to DO next, often naming the exact endpoint (a template with ). The human counterpart to the machine-actionable next.

string
doc_url

Deep link to this code’s docs: https://crate.hosaka.fm/docs/api#error-. Auto-populated for catalogued codes.

string
param

The specific request parameter that caused the failure (e.g. “key”, “q”), so a client can point at the offending input. Present only when the code declares one.

string
next

A copy-pasteable, fully-formed corrected call (a concrete URL, NOT a template) an agent can fire verbatim to recover — the machine-actionable counterpart to hint. Present only when a handler supplies one.

string
details

Structured validation breakdown — on Zod 400s (invalid_query), an array of { path, message }, one per failed field. Present only when validation specifics are attached.

Array
retry_after_seconds

On a 429 rate_limited response, seconds to wait before retrying (mirrors the Retry-After header). Sleep at least this long, then re-issue the identical request.

number
master_id

Echoed on master_not_found (404) — the master id that did not resolve.

number
Example
{
"error": "invalid_query"
}