{
  "openapi": "3.1.0",
  "info": {
    "title": "VinylAI public data API",
    "version": "1.0.0",
    "summary": "The record-store directory, guide index and artist index behind vinylai.app, as JSON.",
    "description": "A read-only, keyless, CORS-open API over the datasets this site publishes: 1 431 record shops in 77 cities, the cities themselves, the guide index and the artist index. No authentication, no rate limit beyond ordinary CDN fair use, and the same rows the human-readable pages render. Reuse is licensed CC BY 4.0 with a link back.",
    "contact": {
      "name": "VinylAI",
      "url": "https://vinylai.app/contacts/"
    },
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "termsOfService": "https://vinylai.app/terms/"
  },
  "servers": [
    {
      "url": "https://vinylai.app/api/v1",
      "description": "Static origin behind Cloudflare"
    }
  ],
  "paths": {
    "/record-stores.json": {
      "get": {
        "operationId": "getRecordStores",
        "summary": "Every record shop in the directory",
        "description": "Returns all 1 431 shops. `buys_records:false` means unverified, not \"does not buy\". Opening hours, ratings and phone numbers are deliberately absent — see `not_included` in the payload.",
        "responses": {
          "200": {
            "description": "The store directory",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreDirectory"
                }
              }
            }
          }
        }
      }
    },
    "/cities.json": {
      "get": {
        "operationId": "getCities",
        "summary": "Cities covered, with store counts",
        "responses": {
          "200": {
            "description": "The city index",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CityIndex"
                }
              }
            }
          }
        }
      }
    },
    "/guides.json": {
      "get": {
        "operationId": "getGuides",
        "summary": "Index of the guides, with the languages each exists in",
        "responses": {
          "200": {
            "description": "The guide index",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/artists.json": {
      "get": {
        "operationId": "getArtists",
        "summary": "Artists with a collecting guide",
        "responses": {
          "200": {
            "description": "The artist index",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/events.json": {
      "get": {
        "operationId": "getEvents",
        "summary": "Recurring vinyl events",
        "responses": {
          "200": {
            "description": "The events",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/status.json": {
      "get": {
        "operationId": "getStatus",
        "summary": "Freshness of the published datasets",
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "StoreDirectory": {
        "type": "object",
        "required": [
          "count",
          "stores"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "examples": [
              1431
            ]
          },
          "stores_that_buy_from_the_public": {
            "type": "integer"
          },
          "updated": {
            "type": "string",
            "format": "date"
          },
          "stores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Store"
            }
          }
        }
      },
      "Store": {
        "type": "object",
        "required": [
          "name",
          "city",
          "country",
          "lat",
          "lon",
          "buys_records",
          "page"
        ],
        "properties": {
          "name": {
            "type": "string",
            "examples": [
              "Reckless Records"
            ]
          },
          "slug": {
            "type": "string"
          },
          "city": {
            "type": "string",
            "examples": [
              "London"
            ]
          },
          "country": {
            "type": "string",
            "examples": [
              "United Kingdom"
            ]
          },
          "country_code": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2",
            "examples": [
              "GB"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": "number",
            "description": "WGS84 decimal degrees"
          },
          "lon": {
            "type": "number",
            "description": "WGS84 decimal degrees"
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "store_type": {
            "type": "string",
            "enum": [
              "both",
              "new",
              "used",
              "specialty"
            ]
          },
          "specialties": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "examples": [
              [
                "Jazz",
                "Rock"
              ]
            ]
          },
          "buys_records": {
            "type": "boolean",
            "description": "true = known to buy from the public. false = NOT CONFIRMED, which is not the same as \"does not buy\"."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "VinylAI’s editorial one-liner."
          },
          "page": {
            "type": "string",
            "format": "uri",
            "description": "The city page this shop appears on."
          }
        }
      },
      "CityIndex": {
        "type": "object",
        "properties": {
          "cities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/City"
            }
          }
        }
      },
      "City": {
        "type": "object",
        "required": [
          "city",
          "slug",
          "country",
          "store_count"
        ],
        "properties": {
          "city": {
            "type": "string",
            "examples": [
              "London"
            ]
          },
          "slug": {
            "type": "string",
            "examples": [
              "london"
            ]
          },
          "country": {
            "type": "string"
          },
          "country_code": {
            "type": "string"
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": "number"
          },
          "lon": {
            "type": "number"
          },
          "store_count": {
            "type": "integer"
          },
          "stores_that_buy_from_the_public": {
            "type": "integer"
          },
          "page": {
            "type": "string",
            "format": "uri"
          },
          "pages": {
            "type": "object",
            "description": "The same page in each language it was built in, keyed by language code.",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://vinylai.app/api/"
  }
}
