{
  "openapi": "3.1.0",
  "info": {
    "title": "Eleganza.nl public storefront API",
    "version": "1.0.0",
    "summary": "Read-only catalogue access to the Eleganza.nl designer fashion store.",
    "description": "Eleganza.nl is a Dutch premium designer fashion retailer. This specification describes the public, unauthenticated endpoints that the storefront already serves, so that an agent can read products, sizes, prices and stock without rendering HTML.\n\nTransacting (cart, checkout, payment) is **not** part of this specification. It runs over the Universal Commerce Protocol; see https://www.eleganza.nl/.well-known/ucp for the authoritative, machine-readable list of capabilities this store grants, and https://www.eleganza.nl/agents.md for the rules an agent must follow.\n\nPayment always requires contemporaneous human approval.",
    "contact": {
      "name": "Eleganza customer service",
      "email": "webshop@eleganza.nl",
      "url": "https://www.eleganza.nl/pages/contact"
    },
    "license": {
      "name": "Public catalogue data, for use on behalf of a buyer",
      "identifier": "LicenseRef-Eleganza-Agent-Use"
    },
    "termsOfService": "https://www.eleganza.nl/policies/terms-of-service"
  },
  "servers": [
    {
      "url": "https://www.eleganza.nl",
      "description": "Dutch and German storefront (NL, BE, DE, EU)"
    },
    {
      "url": "https://www.eleganza-shop.com",
      "description": "English storefront (EU and international)"
    }
  ],
  "externalDocs": {
    "description": "Agent instructions, including when to use this store",
    "url": "https://www.eleganza.nl/agents.md"
  },
  "security": [],
  "x-ucp-discovery": "https://www.eleganza.nl/.well-known/ucp",
  "x-ucp-capabilities-are-the-scopes": "This store declares no OAuth scopes. Write access is capability-scoped through UCP; the named, versioned capabilities under `ucp.capabilities` in https://www.eleganza.nl/.well-known/ucp are the scopes. Request only what you need.",
  "x-rate-limit": {
    "scope": "per IP address",
    "on-exceeded": "HTTP 429 with a Retry-After header, in seconds",
    "guidance": "Honour Retry-After. A short backoff is not enough."
  },
  "paths": {
    "/products/{handle}.json": {
      "get": {
        "operationId": "getProduct",
        "summary": "Get one product with all of its variants",
        "description": "Returns a single product including every size as a variant, with its own price, SKU and barcode. Prices are decimal strings.\n\n**This endpoint does not return stock.** For per-size availability use getProductWithAvailability (/products/{handle}.js) instead.",
        "tags": [
          "catalogue"
        ],
        "security": [],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "The product's URL handle, as it appears in /products/{handle} and in the sitemap.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            },
            "example": "golden-goose-super-star"
          }
        ],
        "responses": {
          "200": {
            "description": "The product.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "product"
                  ],
                  "properties": {
                    "product": {
                      "$ref": "#/components/schemas/Product"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/{handle}.js": {
      "get": {
        "operationId": "getProductWithAvailability",
        "summary": "Get one product including live per-size availability",
        "description": "Same product as getProduct, but this is the endpoint that carries `available` per variant. Use this one to answer 'is this in stock in size X'. Note the price format differs: here it is an integer in cents (39000), while /products/{handle}.json returns a decimal string ('390.00').",
        "tags": [
          "catalogue"
        ],
        "security": [],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "The product's URL handle.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            },
            "example": "golden-goose-super-star"
          }
        ],
        "responses": {
          "200": {
            "description": "The product, with availability per variant.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "handle",
                    "title",
                    "variants"
                  ],
                  "properties": {
                    "id": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "handle": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "vendor": {
                      "type": "string"
                    },
                    "price": {
                      "type": "integer",
                      "description": "In cents."
                    },
                    "available": {
                      "type": "boolean",
                      "description": "True if any variant is in stock."
                    },
                    "variants": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VariantWithAvailability"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/collections/{handle}/products.json": {
      "get": {
        "operationId": "listCollectionProducts",
        "summary": "List the products in a collection",
        "description": "Walk a collection page by page. Use handle `all` for the whole catalogue. Stop when a page returns an empty list.",
        "tags": [
          "catalogue"
        ],
        "security": [],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "Collection handle, for example a brand ('golden-goose') or `all`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            },
            "example": "all"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Products per page. Capped at 250.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of products. An empty list means you have reached the end.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "products"
                  ],
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/search/suggest.json": {
      "get": {
        "operationId": "suggestProducts",
        "summary": "Search the catalogue",
        "description": "Fuzzy, type-ahead style search over products. Use this to turn a buyer's phrasing ('white golden goose sneakers size 42') into handles you can then read with getProduct.",
        "tags": [
          "catalogue"
        ],
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "The search terms.",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "moncler jas dames"
          },
          {
            "name": "resources[type]",
            "in": "query",
            "required": false,
            "description": "Which resources to search.",
            "schema": {
              "type": "string",
              "default": "product",
              "enum": [
                "product",
                "collection",
                "article",
                "page",
                "query"
              ]
            }
          },
          {
            "name": "resources[limit]",
            "in": "query",
            "required": false,
            "description": "Results per resource type. Capped at 10.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuggestResult"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/.well-known/ucp": {
      "get": {
        "operationId": "getUcpDiscovery",
        "summary": "Universal Commerce Protocol discovery document",
        "description": "The authoritative, machine-readable declaration of what this store supports and what an agent may be granted: supported UCP versions, service endpoints, named capabilities (these are the scopes) and payment handlers. Read this before you transact.",
        "tags": [
          "commerce"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The UCP merchant profile.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ucp"
                  ],
                  "properties": {
                    "ucp": {
                      "type": "object",
                      "description": "See https://ucp.dev for the schema.",
                      "properties": {
                        "version": {
                          "type": "string"
                        },
                        "capabilities": {
                          "type": "object",
                          "description": "Named, versioned capabilities. Treat each key as a scope."
                        },
                        "services": {
                          "type": "object"
                        },
                        "payment_handlers": {
                          "type": "object"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/ucp/mcp": {
      "post": {
        "operationId": "callUcpMcp",
        "summary": "UCP Model Context Protocol endpoint (JSON-RPC 2.0)",
        "description": "The transacting surface: search the catalogue, build a cart and start a checkout. Call `tools/list` first to discover the tools and their schemas. Completing a payment requires contemporaneous approval from the human buyer; an agent may not complete a checkout on its own.\n\nCanonical endpoint: https://eleganza-production.myshopify.com/api/ucp/mcp",
        "tags": [
          "commerce"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "422": {
            "description": "JSON-RPC error, for example a missing agent profile on discovery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/agents.md": {
      "get": {
        "operationId": "getAgentInstructions",
        "summary": "Agent instructions, including when to use this store",
        "description": "Markdown. Mirrored at /llms.txt and /llms-full.txt.",
        "tags": [
          "discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The agent instructions.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "Sitemap index for every public URL",
        "description": "XML sitemap index; follow the child sitemaps for products, collections, pages and blog articles.",
        "tags": [
          "discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The sitemap index.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "catalogue",
      "description": "Read products, sizes, prices and stock."
    },
    {
      "name": "commerce",
      "description": "Discover and transact over UCP."
    },
    {
      "name": "discovery",
      "description": "Find your way around the store."
    }
  ],
  "components": {
    "securitySchemes": {},
    "schemas": {
      "Product": {
        "type": "object",
        "required": [
          "id",
          "handle",
          "title",
          "variants"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Shopify-productnummer, stabiel."
          },
          "handle": {
            "type": "string",
            "description": "URL-sleutel, bv. 'golden-goose-super-star-wit'."
          },
          "title": {
            "type": "string"
          },
          "vendor": {
            "type": "string",
            "description": "Het merk."
          },
          "product_type": {
            "type": "string",
            "description": "Categorie, bv. 'Sneakers'."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "body_html": {
            "type": "string",
            "description": "Omschrijving als HTML."
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            }
          },
          "images": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Image"
            }
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Option"
            }
          }
        }
      },
      "Variant": {
        "type": "object",
        "required": [
          "id",
          "title",
          "price"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "title": {
            "type": "string",
            "description": "De maat, bv. '42'."
          },
          "option1": {
            "type": [
              "string",
              "null"
            ]
          },
          "option2": {
            "type": [
              "string",
              "null"
            ]
          },
          "option3": {
            "type": [
              "string",
              "null"
            ]
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "barcode": {
            "type": [
              "string",
              "null"
            ],
            "description": "EAN-13 waar we die hebben."
          },
          "price": {
            "type": "string",
            "description": "Prijs als decimale tekst, bv. '395.00'. Valuta volgt de markt van de koper."
          },
          "compare_at_price": {
            "type": [
              "string",
              "null"
            ],
            "description": "Oorspronkelijke prijs bij korting."
          },
          "requires_shipping": {
            "type": "boolean"
          },
          "taxable": {
            "type": "boolean"
          },
          "position": {
            "type": "integer"
          },
          "inventory_management": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "VariantWithAvailability": {
        "type": "object",
        "required": [
          "id",
          "title",
          "price",
          "available"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "title": {
            "type": "string",
            "description": "De maat, bv. '42'."
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "barcode": {
            "type": [
              "string",
              "null"
            ],
            "description": "EAN-13 waar we die hebben."
          },
          "price": {
            "type": "integer",
            "description": "Prijs in CENTEN, bv. 39000 voor 390 euro. Anders dan op .json, waar het '390.00' is."
          },
          "compare_at_price": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Oorspronkelijke prijs in centen."
          },
          "available": {
            "type": "boolean",
            "description": "True als deze maat nu te bestellen is. Dit veld bestaat ALLEEN op .js."
          },
          "featured_image": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Image"
              },
              {
                "type": "null"
              }
            ]
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Image": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "src": {
            "type": "string",
            "format": "uri"
          },
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "alt": {
            "type": [
              "string",
              "null"
            ]
          },
          "variant_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          }
        }
      },
      "Option": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Bv. 'Maat'."
          },
          "position": {
            "type": "integer"
          },
          "values": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "SuggestResult": {
        "type": "object",
        "properties": {
          "resources": {
            "type": "object",
            "properties": {
              "results": {
                "type": "object",
                "properties": {
                  "products": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "title": {
                          "type": "string"
                        },
                        "handle": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string"
                        },
                        "price": {
                          "type": "string"
                        },
                        "available": {
                          "type": "boolean"
                        },
                        "vendor": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer"
            ]
          },
          "method": {
            "type": "string",
            "description": "For example `initialize`, `tools/list` or `tools/call`."
          },
          "params": {
            "type": "object"
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer",
              "null"
            ]
          },
          "result": {
            "type": "object"
          },
          "error": {
            "$ref": "#/components/schemas/Error"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "description": "Structured error. Always has a code you can branch on and a message you can show a human.",
        "properties": {
          "code": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Machine-readable error code."
          },
          "message": {
            "type": "string",
            "description": "What went wrong, in plain words."
          },
          "data": {
            "type": "object",
            "description": "Extra context, and where available a hint on how to resolve it."
          }
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "No such product or collection. Check the handle against the sitemap.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "code": 404,
              "message": "Not Found",
              "data": {
                "hint": "Verify the handle via /sitemap.xml or suggestProducts."
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests from this IP.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "code": 429,
              "message": "Rate limited",
              "data": {
                "hint": "Wait for Retry-After seconds. A short backoff is not enough."
              }
            }
          }
        }
      }
    }
  }
}
