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 a 308 Permanent Redirect to 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 return 410 Gone with a Link to 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.

  1. 60 days before sunset — this guide is published.
  2. 30 days before sunset/api/v1/* responses carry Deprecation: true + Sunset: <date> + Link: <v2-path>; rel="successor-version" (RFC 8594); v1 still serves normally.
  3. Sunset day — keepers 308-redirect to v2; demoted routes 410.

See the versioning policy for the full contract.