Instrument catalog
The catalog is a read-only API over the instruments Mr Charles knows: a taxonomy of instrument types (from grand pianos to triangles, in several languages, with an openly licensed picture each), models by manufacturer with specifications, identifiers (GTIN/UPC/EAN, MPN, SKU), images and variants (sizes, finishes, each with its own barcode).
All paths are under https://api.mrcharles.app/api/v1/instruments (api-pre.mrcharles.app in the sandbox). Responses follow the common envelope: { "success": true, "data": …, "meta": … }.
Authentication and limits
Section titled “Authentication and limits”| Caller | Header | Limit |
|---|---|---|
| Anonymous | none | 120 requests per minute per IP |
| Shop / integration | X-API-Key: mck_… | the key’s own limit (default 600 per minute) |
Ask [email protected] for a key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 includes Retry-After. An unknown or revoked key answers 401 INVALID_API_KEY / API_KEY_REVOKED.
Taxonomy
Section titled “Taxonomy”The taxonomy is a tree: category → group → family → sub-type. Every node is a family with a kind:
kind | Meaning | Examples |
|---|---|---|
group | Navigation only; holds no models | Cymbals, Drum kits and sets, Guitars |
instrument | An instrument type | Alto saxophone, Cajón, Grand piano |
set | Several pieces sold together | Drum kit, Shell pack, Cymbal pack, Hardware pack |
component | A piece of a set or of an instrument | Snare drum, Crash cymbal, Hi-hat stand, Mouthpiece, Pickup |
accessory | Used with an instrument | Drumsticks, Straps, Cases, Stands |
consumable | Wears out and is replaced | Drumheads, Strings, Reeds, Picks |
Families relate to each other: component_of (a snare is a component of a drum kit), accessory_for (sticks for drums and cymbals), consumable_for (heads for snares). A relation declared on a group applies to everything beneath it, and the API resolves that for you: ask for crash-cymbal and you get the accessories declared for Cymbals.
Each family also carries an attribute schema — the specification keys shops should fill for its models (diameter, alloy, weight for cymbals; size, tip, material for sticks), inherited down the tree.
| Endpoint | Notes | |
|---|---|---|
| GET | /taxonomy | The whole tree with kind, labels, imageUrl, modelCount and totalModelCount per node. Cache it; it changes rarely |
| GET | /categories | Ten categories with labels (en, es, ca, fr) |
| GET | /families?category=percussion&kind=component&parent=cymbals | Flat list; every filter optional. parent=none gives top-level families |
| GET | /families/{slug} | One family: ancestors, children, components, partOf, accessories, consumables, usedWith, attributes (?include= to pick) |
| GET | /families/{slug}/attributes · /components · /accessories · /consumables | The same, one list at a time |
{ "slug": "crash-cymbal", "kind": "component", "path": "cymbals/crash-cymbal", "labels": { "en": "Crash cymbal", "es": "Plato crash", "ca": "Plat crash", "fr": "Cymbale crash" }, "ancestors": [{ "slug": "cymbals", "kind": "group" }], "partOf": [{ "slug": "drum-kit", "relation": "component_of" }, { "slug": "cymbal-pack", "relation": "component_of" }], "accessories": [{ "slug": "drumsticks", "via": "cymbals" }, { "slug": "drum-cases-and-bags", "via": "cymbals" }], "consumables": [{ "slug": "cymbal-felts-and-sleeves", "via": "cymbals" }], "attributes": [ { "key": "diameter", "dataType": "number", "unit": "in", "isFilter": true, "inheritedFrom": "cymbals" }, { "key": "alloy", "dataType": "enum", "options": ["B20", "B12", "B10", "B8", "brass", "nickel silver", "stainless steel", "other"], "isFilter": true, "inheritedFrom": "cymbals" }, { "key": "weight", "dataType": "enum", "options": ["paper thin", "extra thin", "thin", "medium thin", "medium", "medium heavy", "heavy", "extra heavy"], "isFilter": true, "inheritedFrom": "cymbals" } ]}Show imageAttribution next to a family picture; the licence requires it for CC BY licences and it is good practice for public-domain ones.
Models
Section titled “Models”| Endpoint | Notes | |
|---|---|---|
| GET | /search?q=&category=&family=&manufacturer=&kind=&sort=&page=&perPage= | Published models; full-text and fuzzy on name, manufacturer and aliases. family= includes everything under that family (cymbals finds crashes and rides); add shallow=true for the family alone. kind= filters by family kind; `sort=newest |
| GET | /search?family=crash-cymbal&spec[diameter]=18&spec[alloy]=B20 | Attribute filters: spec[key]=value for any key in the family’s /attributes |
| GET | /{idOrSlug} | One model |
| GET | /{idOrSlug}?include=all | With specifications, media, identifiers, variants, aliases in one call (include takes a comma list) |
| GET | /{idOrSlug}/specifications · /media · /identifiers · /variants · /aliases | The same, one resource at a time |
| GET | /manufacturers?q= · /manufacturers/{idOrSlug} | Brands |
media only lists images whose rights were checked by a person and that carry a usable licence; url may be on our origin (/instruments/image?u=…) when the manufacturer’s CDN refuses cross-site loads.
Lookup by barcode or part number
Section titled “Lookup by barcode or part number”| Endpoint | Notes | |
|---|---|---|
| GET | /lookup?gtin=810054347026 | Also upc=, ean=, barcode= (any padded form is accepted), mpn=, sku= |
{ "instrument": { "slug": "kala-west-coast-woods-tenor-xl-ukulele", "manufacturerName": "Kala", "familySlug": "ukulele", "…": "…" }, "identifier": { "identifierType": "upc", "value": "810054347026", "variantId": "a1f6…" }}identifier.variantId is set when the barcode belongs to one variant (a size or finish). 404 RESOURCE_NOT_FOUND when nothing carries the identifier.
Keeping a copy in sync
Section titled “Keeping a copy in sync”| Endpoint | Notes | |
|---|---|---|
| GET | /changes?since=2026-10-01T00:00:00Z&page=1&perPage=100 | Published and deprecated models changed at or after since, oldest first |
Store the last updatedAt you processed and pass it back as since; overlapping by a second is fine (rows repeat, ids do not change). A model whose status is deprecated was withdrawn by the manufacturer: keep it for history, stop offering it.
Errors
Section titled “Errors”Standard errors plus:
| Code | Meaning |
|---|---|
INVALID_API_KEY | Unknown key |
API_KEY_REVOKED | Key revoked by an administrator |
RATE_LIMITED | Over the limit; see Retry-After |
VALIDATION_ERROR | Missing or malformed since, or no identifier given to /lookup |
Where the data comes from
Section titled “Where the data comes from”Manufacturers’ own catalogs (their stores’ public product data), reviewed before publication; instrument types from Wikidata and Wikimedia Commons. Prices are not part of the catalog.