Skip to content

Fleet substrate dictionary — structured JSON (per-entry, for agents)

GET
/api/v2/semantics/dictionary.json
curl --request GET \
--url https://crate.hosaka.fm/api/v2/semantics/dictionary.json \
--header 'X-API-Key: <X-API-Key>'

The structured-JSON companion to GET /api/v2/semantics/dictionary (markdown): the SAME dictionary emitted per-entry so an agent reads ONE metric’s plain-language meaning (.entries["aura"].audience_blurb) instead of parsing the ~68 KB markdown. Served VERBATIM — byte-identical to wintermute’s dictionary.json, so entries is TOP-LEVEL (no crate envelope shadowing it); crate vendor provenance travels in response headers (x-dictionary-source-sha, x-dictionary-vendored-at). Facade fields only (audience_blurb / scale_bands / honest_limits / caveats / clock_class / formula_protected / as_of / producer / source_sha / surface) — no formula or raw-magnitude field. schema_version is 1 (additive-only within a major — pin the major, tolerate unknown additive fields). Keyed (X-API-Key); pure/static (no DB checkout). Refreshed on producer pin-bumps.

The structured dictionary (schema_version 1): schema_version + generator + per-entry facades under entries.

Media type application/json
object
schema_version
required

Dictionary JSON contract version (1). Additive-only within a major.

integer
generator
required

The wintermute generator that emitted the dictionary.

string
entries
required

Per-entry facades keyed by entry name (e.g. “aura”). ~35 entries.

object
key
additional properties
object
audience_blurb
required

Plain-language definition of what the metric/entry means.

string
scale_bands
required

Human-readable scale/interpretation bands.

Array<string>
honest_limits
required

What the metric does NOT measure.

string | null
caveats
required

Interpretation caveats.

Array<string>
clock_class
required

The refresh clock class.

string | null
formula_protected
required

Whether the underlying formula is withheld (facade-only).

boolean
as_of
required

As-of date of the entry.

string | null
producer
required

The producing repo.

string | null
source_sha
required

Per-entry source SHA — the freshness key.

string | null
surface
required

The pins identifier / producer surface this entry maps to.

string | null
Example generated
{
"schema_version": 1,
"generator": "example",
"entries": {
"additionalProperty": {
"audience_blurb": "example",
"scale_bands": [
"example"
],
"honest_limits": "example",
"caveats": [
"example"
],
"clock_class": "example",
"formula_protected": true,
"as_of": "example",
"producer": "example",
"source_sha": "example",
"surface": "example"
}
}
}
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.

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"
}