Skip to content

Cluster-first canonical artist dossier (cluster_id hex OR slug)

GET
/api/v2/artist/{key}
curl --request GET \
--url https://crate.0xhoneyjar.xyz/api/v2/artist/example \
--header 'X-API-Key: <X-API-Key>'

Cycle-2b — the v2 cluster-first headline resource: the same exhaustive artist dossier as v1, addressed by the canonical cluster_id (64-hex, prime key) OR a human slug, plus the v2 ?fields= sparse-fieldset. Default = the full dossier in ONE round-trip; ?fields= opts OUT to trim to the named top-level facets (unknown field → 400 invalid_fields with the valid set + a copy-pasteable example). A 64-hex key resolves identity DIRECTLY from the cluster_id (OBSERVED tier, never re-anchors onto a same-name Discogs row). discogs:/mbid: locators are not a canonical address (→ 400 here) → resolve them to a cluster_id first via GET /api/v2/resolve (the response next field is the ready-to-call URL), then call /api/v2/artist/{cluster_id}. Keyed (X-API-Key); unresolved → 200 identity:null (honest-gap), not 404.

key
required
string
>= 1 characters <= 200 characters
fields

Comma-separated top-level facets to KEEP (opt-out trim). Omit for the full dossier (one round-trip). An unknown field → 400 invalid_fields with the valid set + an example.

string

Artist dossier contract (default-rich; trimmed when ?fields= is supplied)

Media type application/json
object
contract_version
required
string
grain
required
string
Allowed values: artist
slug
required
string
display
required
string
id
required
number | null
cluster_id
required

Crate’s CANONICAL artist identity — a pe-norm-v1 hex string. The SAME artist across Discogs, MusicBrainz and Bandcamp collapses to ONE cluster_id, so this is the key you store and the key you address every artist surface off of (/artist/{key} takes a 64-hex cluster_id directly). WHY IT MATTERS: it is crate’s prime IP — the non-Discogs long-tail join key; discogs_artist_id / mbid are mere leaf coordinates onto it. GOTCHA: it is an OPAQUE string — pass it through verbatim, NEVER numericize, parse, or compare it as a number. null is an HONEST GAP (the name/link couldn’t be resolved to a cluster), NOT an error — you still get HTTP 200. A 64-hex cluster_id always resolves at OBSERVED tier (resolved_via:‘cluster’), never re-anchored onto a same-name Discogs row.

string | null
resolved_via
required

The binding TIER — how trustworthy the identity match is. ‘discogs’ = canonical, Discogs-bound (verified). ‘cluster’ = OBSERVED/UNVERIFIED identity inferred from the seen booking graph with no Discogs bind. null = the lookup did not resolve at all (honest gap). WHY IT MATTERS: it is a trust signal you must respect — a ‘cluster’ result is crate showing you what it can SEE in the booking graph, not what it has verified. GOTCHA: surface a ‘cluster’ result as flagged/unverified, NEVER as canonical truth; do not silently merge a ‘cluster’ artist with a verified one. A bare 64-hex key always comes back ‘cluster’ by design (it skips the cc0_artists lookup so a hex address never re-anchors onto a same-name Discogs row).

string | null
Allowed values: discogs cluster
identity
required
object
discogsArtistId
required
number | null
clusterId
required
string | null
resolvedVia
required
string
Allowed values: discogs cluster
name
required
string
realname
required
string | null
profile
required
string | null
urls
required
Array<string>
aliases
required
Array<string>
behavioral
required
object
state
required
string
signals
required
object
ownerReach
required
Any of:
object
kind
required
string
Allowed values: count
value
required
number
wantlistDemand
required
Any of:
object
kind
required
string
Allowed values: count
value
required
number
collectorCoownership
required
number | null
communityFootprint
required
number | null
travelsWith
required
Array
workCount
required
number | null
primaryGenre
required
string | null
primaryStyles
required
Array<string>
masterCountWithGenre
required
number | null
editorial
required
object
state
required
string
signals
across_the_web
required
object
count
required
number
links
required
Array<object>
object
source
required
string
sourceSubtype
required
string | null
url
required
string
title
required
string | null
description
required
string | null
confidence
required
number | null
journalism
required
object
state
required
string
signals
required
object
pressCount
required
number
reviewCount
required
number
interviewCount
required
number
featureCount
required
number
items
required
Array
connections
required
object
state
required
string
signals
required
object
count
required
number
related
required
Array
emergence
required
object
state
required
string
signals
required
object
emergenceTier
required
string
momentumTier
required
string
emergenceScore
required
number
momentumScore
required
number
establishmentDelta
required
number
eventsRecent
required
number
isFreshBreakout
required
boolean
isUnsigned
required
boolean
breakout
required
object
state
required
string
signal
required
object
emergenceTier
required
string
corroboration
required
string
pressCount
required
number
compositions
required
object
state
required
string
works
required
Array<object>
object
workMbid
required
string
workName
required
string
ownerReach
required
number
versionCollectors
required
number
versionDepth
required
number
nRecordingsGlobal
required
number
tier_presence
required
object
state
required
string
signals
required
object
spansTiers
required
boolean
playsClubs
required
boolean
playsFestivals
required
boolean
clubEvents
required
number
festivalEditions
required
number
firstClubAt
required
string | null
lastClubAt
required
string | null
firstFestivalAt
required
string | null
lastFestivalAt
required
string | null
early_demand
required
object
state
required
string
signals
required
object
ownerReach
required
Any of:
object
kind
required
string
Allowed values: count
value
required
number
wishlistDemand
required
Any of:
object
kind
required
string
Allowed values: count
value
required
number
earliestSupportedAt
required
string | null
earliestWishedAt
required
string | null
demandCoverage
required
number | null
wishedCoverage
required
number | null
alsoOwnDegree
required
number | null
bandcamp_emergence
required
object
state
required
string
signals
required
object
emergenceClass
required
string
demandLead
required
number
demandRatio
required
number | null
ownerReach
required
number | null
wishlistDemand
required
number | null
distinctReleases
required
number | null
earliestWishedAt
required
string | null
artwork
required
object
state
required
string
items
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
dated_appearance
required
object
state
required
string
signals
required
object
count
required
number
sources
required
Array<object>
object
sourceKind
required
string
firstAppearanceDate
required
string | null
latestAppearanceDate
required
string | null
appearanceCount
required
number
network_position
required
object
state
required
string
signals
required
object
degree
required
number
weightedDegree
required
number
resolvedNeighbourRatio
required
number | null
recentDegree
required
number
establishmentDelta
required
number | null
airplay_breadth
required
object
state
required
string
signals
required
object
firstAirplayDate
required
string | null
latestAirplayDate
required
string | null
airplayCount
required
number
distinctStations
required
number
distinctVenues
required
number
distinctDjs
required
number
brokerage
required
object
state
required
string
signals
required
object
degree
required
number
effectiveSize
required
number | null
brokerageScore
required
number | null
brokerageTier
required
string
lead_time
required
object
state
required
string
signals
required
object
pressToAirplayDays
required
number
undergroundToBookingDays
required
number
bandcamp_tastemaker
required
object
state
required
string
signals
required
object
supporterCohortSize
required
number
aesq
required
number
aesqMedian
required
number | null
aesqRw
required
number | null
meanFirstBuyerEarliness
required
number | null
live_demand
required
object
state
required
string
signals
required
object
demandTier
required
string
demandMomentumScore
required
number | null
eventsTracked
required
number
eventsSoldOut
required
number
distinctProviders
required
number
distinctPromoters
required
number
avgFillFraction
required
number | null
maxSoldOutLeadDays
required
number | null
editorial_attention
required
object
state
required
string
signals
required
object
memberCount
required
number
sourceRepoCount
required
number
firstObservedAt
required
string | null
latestObservedAt
required
string | null
web_presence
required
object
state
required
string
signals
required
object
bandcampUrl
required
string | null
soundcloudUrl
required
string | null
instagramUrl
required
string | null
websiteUrl
required
string | null
discogsArtistIdClaimed
required
number | null
raStatus
required
string | null
followerCount
required
number | null
country
required
string | null
firstEventAt
required
string | null
editorial_canon
required
object
state
required
string
signals
required
object
pickCount
required
number
picks
required
Array<object>
object
relation
required
string
polarity
required
string | null
confidence
required
number | null
assertedBy
required
string
isDirectQuote
required
boolean
speakerName
required
string | null
objectName
required
string
discography
required
object
state
required
string
signals
required
object
clusterId
required
string | null
total
required
number
shown
required
number
truncated
required
boolean
entries
required
Array<object>
object
discogsMasterId
required
number
representativeName
required
string | null
isPrimary
required
boolean
billingPosition
required
number
_links
required
object
master
required
string
overMerge
required
object
discogsArtistIdCount
required
number
folded
required
boolean
observedAt
required
string | null
provenance
required
Array<object>
object
field
required
string
producer
required
string
sourceTable
required
string
refreshCadence
required
string
tier
required
string
honestGapState
required
string
detailAnchor
string
generated_at
required
string
Example
{
"grain": "artist",
"cluster_id": "a3f9c1e84b2d70f6a3f9c1e84b2d70f6a3f9c1e84b2d70f6a3f9c1e84b2d70f6",
"resolved_via": "discogs",
"identity": {
"resolvedVia": "discogs"
},
"behavioral": {
"signals": {
"ownerReach": {
"kind": "count"
},
"wantlistDemand": {
"kind": "count"
}
}
},
"early_demand": {
"signals": {
"ownerReach": {
"kind": "count"
},
"wishlistDemand": {
"kind": "count"
}
}
},
"artwork": {
"items": [
{
"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.0xhoneyjar.xyz/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.0xhoneyjar.xyz/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.0xhoneyjar.xyz/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.0xhoneyjar.xyz/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"
}