The VinylAI data API

Everything this site knows about record shops, and everything it has written about vinyl, is also published as JSON. No key, no account, no rate limit beyond ordinary fair use, CORS open to any origin, licensed CC BY 4.0. 1,431 shops in 77 cities across 19 countries, an index of 203 guides in eight languages, and 95 artist pages.

Start here

One request tells you the shape of everything else:

curl https://vinylai.app/api/v1/index.json

Then take the dataset you want. Every file is static, served from the CDN, and regenerated on each site build:

curl https://vinylai.app/api/v1/record-stores.json
curl https://vinylai.app/api/v1/cities.json
curl https://vinylai.app/api/v1/guides.json

If you only need to know whether anything changed, fetch status.json — it is under a kilobyte and carries generated_at plus the row count of every dataset. Do that instead of refetching the store directory, which is about 840 KB uncompressed.

The endpoints

EndpointSizeWhat it returns
/api/v1/record-stores.json 1,431 shops Every shop in the directory: name, address, WGS84 coordinates, website, specialities, and whether it buys records from the public.
/api/v1/cities.json 77 cities The cities covered, each with a store count, a count of shops that buy from the public, and the page URL in every language it was built in.
/api/v1/guides.json 203 guides Index of the written reference — topic, cluster, and which of the eight languages each guide exists in.
/api/v1/artists.json 95 artists Artists with a collecting guide: primary genre, active years, country, and a pointer into Discogs’ catalogue.
/api/v1/events.json 10 events Recurring vinyl events — Record Store Day and the record-fair calendar — with the organiser’s own site as the authority.
/api/v1/status.json — When each dataset was last rebuilt, and how many rows it holds. Check this instead of refetching a megabyte.
/api/v1/openapi.json — OpenAPI 3.1 over all of the above.

The machine description of all of it is OpenAPI 3.1, and the RFC 9727 catalogue that points at it is /.well-known/api-catalog.

What the fields actually mean

This is the section a schema cannot carry, and it is the one worth reading. Each of these has produced a confidently wrong answer somewhere.

buys_records: false means unconfirmed, not “does not buy”

210 of the 1,431 shops are confirmed to buy records from the public. The other rows are not shops that refuse — they are shops nobody has checked. Most independent record shops buy. So a true is a positive fact you may state; a false is an absence of information, and the correct phrasing is “not confirmed in the directory, call and ask”. Telling someone a shop will not take their collection on the strength of a false is the single most likely way to be wrong with this data.

Four fields are missing on purpose

The store rows carry no opening hours, no ratings or review counts, no telephone numbers and no third-party place identifiers. None of that is an oversight:

  • Opening hours are the field that goes stale fastest, and being wrong about them sends somebody across a city to a closed shop. They are on the city page, next to the map, where they are read by a person who can see how old the page is.
  • Ratings and review counts shown on the city pages are a third party’s aggregated content. Republishing them here under a CC BY grant would be licensing something that is not ours to license — and a rating frozen at build time misinforms besides.
  • Telephone numbers. 1,277 business phone numbers in one machine-readable file is a cold-call list, whatever it is labelled. website reaches the shop and cannot be auto-dialled in bulk.
  • Place identifiers from third-party mapping services mean nothing outside those services and are not republished.

The not_included block inside record-stores.json says the same thing inside the payload, because a consumer reads the data and not the documentation.

page and pages

page is the canonical English URL. pages is an object keyed by language code holding the same page in every language it was actually built in — which is not always all eight. Link the language your reader is in; do not construct /{lang}/… yourself, because a URL for a translation that does not exist is a 404 you invented.

languages on a guide is the real set

Every guide exists in English. A handful are missing one or two of the other seven, so the array is the built truth rather than a constant. Same rule as above: read it, do not assume it.

store_type is coarse

Almost every row reads both, meaning the shop sells new and secondhand. It is a low-resolution field and the shop’s own website is the better authority on what it actually stocks. specialties is more useful where it is populated.

lat / lon

WGS84 decimal degrees, the same convention every mapping library expects. They locate the shop, not the centre of the city; the city’s own coordinates are in cities.json.

discogs_artist_id is a pointer, not a copy

The artist rows carry the artist’s identifier in Discogs’ catalogue so you can go and look up a discography there. No Discogs release, price or inventory data is reproduced in this API.

Freshness

These are static files rebuilt with the site. The failure mode worth watching is not a 5xx — it is a stale generated_at in status.json. Shops close and move; for anything that involves somebody travelling, the honest answer includes “call first”.

Every page, as markdown

HTML is an expensive way to read a page. Each of this site’s pages has a markdown twin that is roughly a tenth of the bytes and carries the same words. Two ways to get it — agent stacks split about evenly between them:

curl -H "Accept: text/markdown" https://vinylai.app/record-stores/london/
curl https://vinylai.app/record-stores/london/index.md

Both work for any page on the site, in any of the eight languages. The twins carry a provenance footer with the source URL and the licence, because a retrieved passage travels alone. They are served with X-Robots-Tag: noindex — the same content at a second URL should not be indexed twice, and that header does not stop an AI crawler reading the file.

For the whole site at once: /llms.txt is the index, and /llms-full.txt carries the primary pages in full.

MCP and A2A

An MCP server runs at https://vinylai.app/mcp (Streamable HTTP, JSON-RPC 2.0, no authentication). It turns the same data into named tools, which is the difference between an assistant that can answer “where can I sell my records in Berlin” and one that answers it correctly.

curl -X POST https://vinylai.app/mcp \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Five read-only tools: find_record_stores, find_stores_that_buy_vinyl, list_store_cities, find_vinyl_guide and get_artist_guide. Every one returns the source URL next to the answer, so an agent that used a tool still has a page to cite. The card is at /.well-known/mcp/server-card.json.

An A2A endpoint answering the same questions in natural language is at https://vinylai.app/a2a, with its card at /.well-known/agent-card.json. It is deliberately not a language model: it routes on the entities it finds and says “I could not find that” rather than improvising.

Agent skills

Four SKILL.md documents, indexed at /.well-known/agent-skills/index.json and digest-pinned, so a client can verify it loaded the bytes we published:

  • find-record-stores — Locating shops in a city, and knowing when the directory simply does not cover a place.
  • sell-vinyl-records — Which shops buy from the public, and why a shop’s offer is not a marketplace price.
  • identify-a-vinyl-pressing — Runout etchings, catalogue numbers, country of manufacture — and what a photo of a cover can never settle.
  • value-a-vinyl-record — The four things that decide a record’s value and the three ways the usual answer is wrong.

Discovery

An agent that has fetched anything from this origin can find the rest from the response headers alone — every response carries Link headers for the API catalogue, the OpenAPI description, this page and /llms.txt. The documents themselves:

DocumentWhat it is
/.well-known/api-catalogRFC 9727 linkset: service-desc, service-doc, status and licence for the API.
/.well-known/ai-catalog.jsonARD capability manifest — every dataset, skill and server card, with the queries each answers.
/.well-known/agent-skills/index.jsonAgent Skills Discovery 0.2.0 index; four SKILL.md documents, each digest-pinned.
/.well-known/mcp/server-card.jsonThe MCP server card (SEP-1649).
/.well-known/agent-card.jsonThe A2A agent card.
/.well-known/oauth-protected-resourceRFC 9728 metadata declaring, explicitly, that there is no authorization server and nothing to authenticate.
/auth.mdWhat an agent may do here, in prose. Short version: read everything, register nothing.
/llms.txtIndex of the whole site as markdown.
/llms-full.txtFull text of the primary pages as one document.

What there is no API for

Worth saying plainly, because the absence is a property of the product rather than a gap we forgot to fill:

  • No writes. Nothing on this origin accepts data. A shop that wants its listing corrected or added writes to us through the contact page; there is no endpoint for it and no key that would open one.
  • No user data, and no way to act for a user. Scanning a record, tracking a collection and buying a subscription all happen inside the app on the person’s own device, authenticated by their App Store or Google Play account. There is no server-side user API, so there is no credential an agent could hold — which is also why there is no OAuth authorization server here and why we do not publish metadata for one. The empty protected-resource document says exactly that, in the vocabulary a client already parses.
  • No record identification endpoint. Photographing a record and identifying the pressing is what the VinylAI app does, on the device. It is not exposed as a public API.
  • No Discogs data. We link to Discogs and we carry artist identifiers into it. We do not redistribute their catalogue, prices or inventory.

Licence and attribution

Everything under /api/v1/ is licensed CC BY 4.0. Use it commercially, build on it, redistribute it — with a link back to vinylai.app or, better, to the specific page the row came from. That attribution is the whole price.

The grant covers VinylAI’s own editorial text and the compilation. It is not a licence to any third party’s content, and none is included — which is precisely why the four fields above are absent.

Stability and fair use

/api/v1/ is versioned in the path. Fields will be added; existing fields will not change meaning under the same name. If something has to change incompatibly it becomes /api/v2/ and v1 stays where it is.

These are static files behind a CDN, so there is no quota to exceed and nothing to throttle. Cache them anyway: they change when the site is rebuilt, and status.json exists so you can find that out cheaply. Questions, corrections and anything that looks wrong: the contact page.

What's your vinyl worth? Scan any record, get instant value
Try Free