{
  "openapi": "3.1.1",
  "info": {
    "title": "Vintonland Product Catalogue API",
    "version": "1.0.0",
    "summary": "The Vintonland sticker shop as JSON: one read-only, unauthenticated endpoint.",
    "description": "Vintonland is an independent, non-commercial site about Vinton, Virginia. It publishes\none machine-readable endpoint: the shop catalogue, with live prices, variants and stock\nstate as of the last build.\n\nThis is a STATIC FILE on a CDN, not a service. There is no key, no account, no session,\nno rate limit and no way to write. Every caller gets identical bytes, and the response\nchanges only when the site is rebuilt — `generatedAt` in the body is the real freshness.\n\nFor everything the site publishes that is not this endpoint — Markdown variants of every\npage, llms.txt, the sitemap and JSON-LD — see the documentation link below.",
    "contact": {
      "name": "Vintonland",
      "email": "hello@vinton.land",
      "url": "https://vinton.land/contact/"
    },
    "license": {
      "name": "Product data is provided as-is for reference and attribution.",
      "identifier": "CC-BY-4.0"
    }
  },
  "externalDocs": {
    "description": "Vintonland for agents and developers",
    "url": "https://vinton.land/for-agents/"
  },
  "servers": [
    {
      "url": "https://vinton.land",
      "description": "Production. The only deployment; served from Netlify's CDN."
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Catalogue",
      "description": "The shop as data."
    }
  ],
  "paths": {
    "/api/products.json": {
      "get": {
        "operationId": "getVintonlandProductCatalogue",
        "tags": [
          "Catalogue"
        ],
        "summary": "Get the whole Vintonland shop catalogue",
        "description": "Returns every product in the Vintonland shop in one document: handles, titles,\nplain-text descriptions, canonical page URLs, images, and one entry per buyable\nvariant with its price, currency, option values and stock state.\n\nReach for this when someone asks what the Vintonland shop sells, what a sticker\ncosts, which colorways exist, or whether something is in stock. It is the whole\ncatalogue in a single request — there is no search, no pagination and no filter,\nbecause the shop is small enough that paging it would be ceremony.\n\nTakes no parameters and no authentication. Prices are decimal strings; parse them\nwith a decimal type, not a float.",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "The catalogue. Always returned; an empty shop is `count: 0`, not an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductCatalogue"
                },
                "example": {
                  "$schema": "https://schema.org/Product",
                  "generatedAt": "2026-09-16T17:06:27.266Z",
                  "documentation": "https://vinton.land/for-agents/",
                  "specification": "https://vinton.land/openapi.json",
                  "contact": "hello@vinton.land",
                  "currency": "USD",
                  "count": 1,
                  "products": [
                    {
                      "handle": "vinton-badge-sticker",
                      "title": "Badge Sticker",
                      "description": "Printed on thick, durable vinyl with a matte finish. Very sticky. 2.4\" x 2.8\"",
                      "url": "https://vinton.land/shop/vinton-badge-sticker/",
                      "image": "https://vinton.land/img/shop/064d099fe9be6d66.webp",
                      "options": [
                        {
                          "name": "Colorway",
                          "values": [
                            "Classic Pine",
                            "Creamsicle",
                            "Blue Ridge"
                          ]
                        }
                      ],
                      "variants": [
                        {
                          "title": "Classic Pine",
                          "sku": null,
                          "price": "3.0",
                          "currency": "USD",
                          "available": true,
                          "options": {
                            "Colorway": "Classic Pine"
                          },
                          "image": "https://vinton.land/img/shop/064d099fe9be6d66.webp"
                        },
                        {
                          "title": "Creamsicle",
                          "sku": null,
                          "price": "3.0",
                          "currency": "USD",
                          "available": true,
                          "options": {
                            "Colorway": "Creamsicle"
                          },
                          "image": "https://vinton.land/img/shop/558b60f94101974f.webp"
                        },
                        {
                          "title": "Blue Ridge",
                          "sku": null,
                          "price": "3.0",
                          "currency": "USD",
                          "available": true,
                          "options": {
                            "Colorway": "Blue Ridge"
                          },
                          "image": "https://vinton.land/img/shop/a7958cc3182bc4ea.webp"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not returned by this path in a healthy deploy. Documented because every OTHER path under /api/ returns this body, so a caller that guesses a URL gets JSON it can parse rather than an HTML error page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ProductCatalogue": {
        "type": "object",
        "title": "ProductCatalogue",
        "description": "The whole shop as one document, plus the metadata needed to use it.",
        "required": [
          "$schema",
          "generatedAt",
          "documentation",
          "specification",
          "contact",
          "currency",
          "count",
          "products"
        ],
        "additionalProperties": false,
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri",
            "description": "The vocabulary the product fields follow, for a consumer that wants the mapping.",
            "const": "https://schema.org/Product"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When this file was BUILT, not when it was requested. It is a static artefact, so this is the true freshness of the prices below."
          },
          "documentation": {
            "type": "string",
            "format": "uri",
            "description": "The human-readable docs page."
          },
          "specification": {
            "type": "string",
            "format": "uri",
            "description": "This OpenAPI document."
          },
          "contact": {
            "type": "string",
            "format": "email",
            "description": "A mailbox read by a person."
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$",
            "description": "The currency every price in this document uses. The shop sells in one.",
            "examples": [
              "USD"
            ]
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of entries in `products`."
          },
          "products": {
            "type": "array",
            "description": "Every product the shop carries.",
            "items": {
              "$ref": "#/components/schemas/Product"
            }
          }
        }
      },
      "Product": {
        "type": "object",
        "title": "Product",
        "description": "One product in the shop, with every variant.",
        "required": [
          "handle",
          "title",
          "description",
          "url",
          "image",
          "options",
          "variants"
        ],
        "additionalProperties": false,
        "properties": {
          "handle": {
            "type": "string",
            "description": "URL-safe identifier, and the last path segment of `url`.",
            "examples": [
              "vinton-badge-sticker"
            ]
          },
          "title": {
            "type": "string",
            "description": "Display name.",
            "examples": [
              "Badge Sticker"
            ]
          },
          "description": {
            "type": "string",
            "description": "Plain-text description, with line breaks flattened."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Absolute canonical URL of the product page a human would read."
          },
          "image": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Absolute URL of the featured image, or null."
          },
          "options": {
            "type": "array",
            "description": "Every axis of choice.",
            "items": {
              "$ref": "#/components/schemas/ProductOption"
            }
          },
          "variants": {
            "type": "array",
            "description": "Every buyable combination.",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/ProductVariant"
            }
          }
        }
      },
      "ProductOption": {
        "type": "object",
        "title": "ProductOption",
        "description": "One axis of choice, such as Colorway, and every value it can take.",
        "required": [
          "name",
          "values"
        ],
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "description": "The option name as it appears on the product page.",
            "examples": [
              "Colorway"
            ]
          },
          "values": {
            "type": "array",
            "description": "Every value of this option across all variants, in the order the shop lists them.",
            "items": {
              "type": "string"
            },
            "examples": [
              [
                "Classic Pine",
                "Creamsicle",
                "Blue Ridge"
              ]
            ]
          }
        }
      },
      "ProductVariant": {
        "type": "object",
        "title": "ProductVariant",
        "description": "One buyable combination of options, with its own price, stock state and image.",
        "required": [
          "title",
          "sku",
          "price",
          "currency",
          "available",
          "options",
          "image"
        ],
        "additionalProperties": false,
        "properties": {
          "title": {
            "type": "string",
            "description": "The variant name, usually the option values joined.",
            "examples": [
              "Classic Pine"
            ]
          },
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stock keeping unit, or null when the shop has not set one. Often null here."
          },
          "price": {
            "type": "string",
            "description": "The price as a decimal string, not a number, so it survives a round trip without binary floating point rounding it. Parse it with a decimal type.",
            "pattern": "^[0-9]+(\\.[0-9]+)?$",
            "examples": [
              "3.0"
            ]
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code for `price`.",
            "pattern": "^[A-Z]{3}$",
            "examples": [
              "USD"
            ]
          },
          "available": {
            "type": "boolean",
            "description": "True when this variant could be added to a cart at build time."
          },
          "options": {
            "type": "object",
            "description": "The option values that identify this variant, keyed by option name.",
            "additionalProperties": {
              "type": "string"
            },
            "examples": [
              {
                "Colorway": "Classic Pine"
              }
            ]
          },
          "image": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Absolute URL of this variant's image on vinton.land, or null. Images are mirrored onto this origin at build time, so following one costs Shopify nothing."
          }
        }
      },
      "ApiError": {
        "type": "object",
        "title": "ApiError",
        "description": "The body returned for any path under /api/ that does not exist.",
        "required": [
          "error"
        ],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "status",
              "message",
              "resolution",
              "specification",
              "documentation",
              "llmsTxt",
              "endpoints",
              "contact"
            ],
            "additionalProperties": false,
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable identifier.",
                "examples": [
                  "not_found"
                ]
              },
              "status": {
                "type": "integer",
                "description": "The HTTP status sent with this body.",
                "examples": [
                  404
                ]
              },
              "message": {
                "type": "string",
                "description": "One sentence, for a human reading a log."
              },
              "resolution": {
                "type": "string",
                "description": "What to do instead."
              },
              "specification": {
                "type": "string",
                "format": "uri",
                "description": "This OpenAPI document."
              },
              "documentation": {
                "type": "string",
                "format": "uri",
                "description": "The human-readable docs page."
              },
              "llmsTxt": {
                "type": "string",
                "format": "uri",
                "description": "The site index, llmstxt.org format."
              },
              "endpoints": {
                "type": "array",
                "description": "Every endpoint that does exist. There is one.",
                "items": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "contact": {
                "type": "string",
                "format": "email",
                "description": "A mailbox read by a person."
              }
            }
          }
        }
      }
    }
  }
}
