Migrating from /api/v1 to /api/v2
/api/v2 is the cluster-first major: cluster_id is the prime key, and sources (Bandcamp, Discogs, …) and releases attach to an agent (artist / label / festival) rather than being first-class. v2 is otherwise the same data your v1 integration already reads — most routes just move from /api/v1/* to /api/v2/* with an identical response shape.
This guide is the route-by-route map. Until the cutover is scheduled (it's feature-flagged and announced), /api/v1/* keeps serving unchanged — you can migrate on your own timeline.
TL;DR
- Keeper routes (most of the API) move 1:1 to
/api/v2/*. On cutover,/api/v1/*returns a308 Permanent Redirectto the v2 path — method and query string preserved — so a conforming client keeps working through the redirect. Migrate by swapping the path prefix. - Demoted routes (
masters/*,bandcamp/*top-level,dossier/master) have no v2 equivalent. On cutover they return410 Gonewith aLinkto the successor and a JSON body explaining where the data went. These need a real code change (see below). - Operational routes (
signup,usage,stripe/webhook,admin/keys,wayfind/*) are not versioned in this cut — they stay on/api/v1/*.
Keeper routes — swap the prefix (308 on cutover)
| v1 | v2 |
|----|----|
| GET /api/v1 | GET /api/v2 |
| GET /api/v1/openapi.json | GET /api/v2/openapi.json |
| GET /api/v1/resolve | GET /api/v2/resolve |
| GET /api/v1/artist/{key} | GET /api/v2/artist/{key} (+ v2 ?fields= sparse-fieldset) |
| GET /api/v1/label/{key} | GET /api/v2/label/{key} |
| GET /api/v1/search | GET /api/v2/search |
| GET /api/v1/facets | GET /api/v2/facets |
| GET /api/v1/breakouts | GET /api/v2/breakouts |
| GET /api/v1/tastemakers | GET /api/v2/tastemakers |
| GET /api/v1/tastemakers/ones-to-watch | GET /api/v2/tastemakers/ones-to-watch |
| GET /api/v1/dossier/artist/{slug} | GET /api/v2/dossier/artist/{slug} |
| GET /api/v1/dossier/label/{slug} | GET /api/v2/dossier/label/{slug} |
| GET /api/v1/dossier/festival/{slug} | GET /api/v2/dossier/festival/{slug} |
| GET /api/v1/dossier/manifest | GET /api/v2/dossier/manifest |
| POST /api/v1/search-events/observed | POST /api/v2/search-events/observed |
| POST /api/v1/search-events/refined | POST /api/v2/search-events/refined |
Auth is unchanged (same X-API-Key; beacons keep their per-search bearer token). v2 adds the artist ?fields= opt-out trim (default is still the full dossier — one round-trip).
Demoted routes — the data moved (410 on cutover)
In the cluster-first model, releases/records and Bandcamp are dimensions of the artist dossier, not standalone resources.
| Gone v1 route | Where the data is in v2 |
|---------------|--------------------------|
| GET /api/v1/masters/{id} · POST /api/v1/masters/batch · GET /api/v1/dossier/master/{id} | The artist discography dimension: resolve the artist (GET /api/v2/resolve), then GET /api/v2/artist/{cluster_id} — the discography facet carries the master/release detail. Field map: GET /api/v2/dossier/manifest. |
| GET /api/v1/bandcamp/{artistKey} | GET /api/v2/artist/{artistKey} — the bandcamp facet is included in the dossier. |
| GET /api/v1/bandcamp (manifest) · GET /api/v1/bandcamp/release | Bandcamp signals attach per-artist: resolve the artist, then read the bandcamp facet of GET /api/v2/artist/{cluster_id}. |
The per-master dossier (/api/v1/dossier/master/{id}) stays addressable on /api/v1 for as long as v1 lives.
The cluster-first front door
The canonical v2 flow is resolve once, then key everything:
GET /api/v2/resolve?q=Four Tet → { cluster_id, slug, locators, _links }
GET /api/v2/artist/{cluster_id} → the full dossier (identity, behavior, discography, bandcamp, …)
GET /api/v2/artist/{cluster_id}?fields=identity,discography → the same dossier, trimmed
resolve also accepts a pasted link (?url=) or a ?discogs= / ?mbid= id and returns the canonical cluster_id.
Timeline
The cutover is gated behind a feature flag; nothing changes until it's flipped and announced.
- 60 days before sunset — this guide is published.
- 30 days before sunset —
/api/v1/*responses carryDeprecation: true+Sunset: <date>+Link: <v2-path>; rel="successor-version"(RFC 8594); v1 still serves normally. - Sunset day — keepers
308-redirect to v2; demoted routes410.
See the versioning policy for the full contract.