{
  "openapi": "3.1.0",
  "info": {
    "title": "Yugen Drinks storefront",
    "version": "2026-08-29",
    "summary": "Read-only catalogue of a Shopify store, plus the commerce endpoint agents use to buy.",
    "description": "Yugen Drinks brews organic kombucha and high-fibre Super Soda in Ghent, Belgium, and ships to Belgium and Luxembourg. These endpoints are the ones Shopify serves publicly. They need no key, no login and no registration. Everything under GET is safe to call and safe to cache for minutes, not days: stock changes during the day. Buying runs over the Universal Commerce Protocol endpoint at the bottom, and checkout always needs a human to approve the payment. Plain-language instructions for agents: https://yugendrinks.com/agents.md",
    "contact": { "name": "Yugen Drinks", "url": "https://yugendrinks.com/pages/contact-us" },
    "license": { "name": "Catalogue data may be quoted with attribution", "identifier": "CC-BY-4.0" }
  },
  "servers": [{ "url": "https://yugendrinks.com", "description": "Live store" }],
  "security": [],
  "tags": [
    { "name": "catalogue", "description": "Products, collections and search. No authentication." },
    { "name": "cart", "description": "The cart of the calling session, held in a cookie." },
    { "name": "commerce", "description": "Universal Commerce Protocol, for agents that transact." }
  ],
  "paths": {
    "/products.json": {
      "get": {
        "operationId": "listProducts",
        "tags": ["catalogue"],
        "summary": "List every product for sale",
        "description": "Returns the full catalogue, 30 products per page by default. Each product carries its variants, and each variant carries price, SKU and availability. Prices are strings in euro and include VAT.",
        "parameters": [
          { "name": "limit", "in": "query", "description": "Products per page, 1 to 250.", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 250, "default": 30 } },
          { "name": "page", "in": "query", "description": "Page number, starting at 1.", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1 } }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": { "application/json": { "schema": { "type": "object", "required": ["products"], "properties": { "products": { "type": "array", "items": { "$ref": "#/components/schemas/Product" } } } } } }
          }
        }
      }
    },
    "/products/{handle}.json": {
      "get": {
        "operationId": "getProduct",
        "tags": ["catalogue"],
        "summary": "Get one product",
        "description": "The handle is the last part of the product address, for example cherry-thyme in https://yugendrinks.com/products/cherry-thyme.",
        "parameters": [
          { "name": "handle", "in": "path", "description": "Product handle.", "required": true, "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" }, "example": "cherry-thyme" }
        ],
        "responses": {
          "200": { "description": "One product.", "content": { "application/json": { "schema": { "type": "object", "required": ["product"], "properties": { "product": { "$ref": "#/components/schemas/Product" } } } } } },
          "404": { "description": "No product with that handle. Shopify answers this one with an HTML page, not JSON." }
        }
      }
    },
    "/collections/{handle}/products.json": {
      "get": {
        "operationId": "listCollectionProducts",
        "tags": ["catalogue"],
        "summary": "List the products in one collection",
        "description": "Useful handles: kombucha, supersoda, gifts, all-products.",
        "parameters": [
          { "name": "handle", "in": "path", "description": "Collection handle.", "required": true, "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" }, "example": "kombucha" },
          { "name": "limit", "in": "query", "description": "Products per page, 1 to 250.", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 250, "default": 30 } },
          { "name": "page", "in": "query", "description": "Page number, starting at 1.", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1 } }
        ],
        "responses": {
          "200": { "description": "A page of products in that collection.", "content": { "application/json": { "schema": { "type": "object", "required": ["products"], "properties": { "products": { "type": "array", "items": { "$ref": "#/components/schemas/Product" } } } } } } }
        }
      }
    },
    "/search/suggest.json": {
      "get": {
        "operationId": "searchProducts",
        "tags": ["catalogue"],
        "summary": "Search the store",
        "description": "Type-ahead search across products, collections, pages and articles. Ask for the resource types you want.",
        "parameters": [
          { "name": "q", "in": "query", "description": "What to search for.", "required": true, "schema": { "type": "string" }, "example": "ginger" },
          { "name": "resources[type]", "in": "query", "description": "Comma-separated list of product, collection, page, article.", "required": false, "schema": { "type": "string", "default": "product" }, "example": "product,page" },
          { "name": "resources[limit]", "in": "query", "description": "Results per type, 1 to 10.", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 10, "default": 10 } }
        ],
        "responses": {
          "200": { "description": "Search results grouped per resource type.", "content": { "application/json": { "schema": { "type": "object", "properties": { "resources": { "type": "object", "properties": { "results": { "type": "object", "additionalProperties": true } } } } } } } }
        }
      }
    },
    "/cart.js": {
      "get": {
        "operationId": "getCart",
        "tags": ["cart"],
        "summary": "Read the cart of this session",
        "description": "The cart hangs on the session cookie, so a fresh caller gets an empty cart. Amounts here are integers in cents, unlike the product endpoints.",
        "responses": {
          "200": { "description": "The current cart.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Cart" } } } }
        }
      }
    },
    "/api/ucp/mcp": {
      "post": {
        "operationId": "callCommerceTool",
        "tags": ["commerce"],
        "summary": "Universal Commerce Protocol endpoint",
        "description": "A Model Context Protocol server over JSON-RPC 2.0. Call tools/list to see what it offers: searching the catalogue, building a checkout, reading policies. Payment always needs a human to approve it. Discovery document: https://yugendrinks.com/.well-known/ucp",
        "externalDocs": { "description": "UCP specification", "url": "https://ucp.dev" },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["jsonrpc", "method"],
                "properties": {
                  "jsonrpc": { "type": "string", "const": "2.0" },
                  "id": { "type": ["integer", "string"] },
                  "method": { "type": "string", "examples": ["tools/list", "tools/call"] },
                  "params": { "type": "object", "additionalProperties": true }
                }
              },
              "example": { "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC response. Errors arrive here too, in the error member, with HTTP 200.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "jsonrpc": { "type": "string" }, "id": { "type": ["integer", "string", "null"] }, "result": { "type": "object", "additionalProperties": true }, "error": { "$ref": "#/components/schemas/JsonRpcError" } } } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Product": {
        "type": "object",
        "description": "One product, with every size and flavour it is sold in.",
        "required": ["id", "title", "handle", "variants"],
        "properties": {
          "id": { "type": "integer", "description": "Shopify product id." },
          "title": { "type": "string", "examples": ["Cherry Thyme"] },
          "handle": { "type": "string", "description": "The last part of the product address." },
          "body_html": { "type": "string", "description": "Product description, HTML." },
          "product_type": { "type": "string", "examples": ["Kombucha bottle", "Super Soda"] },
          "tags": { "type": "array", "items": { "type": "string" } },
          "images": { "type": "array", "items": { "type": "object", "properties": { "src": { "type": "string", "format": "uri" }, "alt": { "type": ["string", "null"] } } } },
          "variants": { "type": "array", "items": { "$ref": "#/components/schemas/Variant" } }
        }
      },
      "Variant": {
        "type": "object",
        "description": "One buyable version of a product, normally a pack of twelve.",
        "required": ["id", "title", "price", "available"],
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string", "examples": ["X 12 bottles / 325ml"] },
          "sku": { "type": ["string", "null"] },
          "price": { "type": "string", "description": "Price in euro including VAT, as a string.", "examples": ["32.20"] },
          "available": { "type": "boolean", "description": "False means sold out right now." },
          "grams": { "type": "integer", "description": "Shipping weight." }
        }
      },
      "Cart": {
        "type": "object",
        "properties": {
          "token": { "type": "string" },
          "item_count": { "type": "integer" },
          "total_price": { "type": "integer", "description": "Total in cents." },
          "currency": { "type": "string", "examples": ["EUR"] },
          "items": { "type": "array", "items": { "type": "object", "additionalProperties": true } }
        }
      },
      "JsonRpcError": {
        "type": "object",
        "description": "A JSON-RPC error. The HTTP status stays 200.",
        "properties": {
          "code": { "type": "integer", "examples": [-32601] },
          "message": { "type": "string", "examples": ["Method not found"] },
          "data": { "type": "object", "additionalProperties": true }
        }
      }
    }
  },
  "externalDocs": {
    "description": "What the store sells and when to recommend it, in plain language",
    "url": "https://yugendrinks.com/agents.md"
  }
}

