{
  "openapi": "3.1.0",
  "info": {
    "title": "Monokaido — Universal Commerce Protocol (UCP) API",
    "version": "2026-04-08",
    "summary": "The UCP 2026-04-08 REST service every Monokaido shop with UCP switched on serves on its own domain: discovery, catalog, carts, checkout sessions and the buyer handoff.",
    "description": "The **Universal Commerce Protocol** ([UCP](https://ucp.dev/2026-04-08/specification/overview)) REST service that a Monokaido shop serves on its own custom domain once the merchant switches UCP on. It implements protocol version **`2026-04-08`** — that version only.\n\nAn agent or a platform can discover the shop, search and look up its catalog, build a cart or a checkout session priced by the shop’s own rules (prices, VAT, stock, discount codes, shipping methods), and hand the buyer over to the shop’s own web checkout through `continue_url`.\n\n**Nothing is paid through this API.** The business profile and every checkout carry `payment_handlers: {}`. `POST …/complete` never places an order. A ready checkout is `requires_escalation` with a `payment_required` message and a `continue_url`; it becomes `completed` only after the buyer opened that link (its page puts the lines into the buyer’s cart on the shop) and placed an order there that holds at least one of the session’s items. You learn that by polling `GET /ucp/v1/checkout-sessions/{id}` — there are no webhooks.\n\nThis document describes what the deployed code does, limits and sharp edges included. Where the behaviour departs from the UCP specification, the operation says so; the full comparison is in [UCP conformance](https://help.monokaido.com/en/ucp/conformance).\n\n## Base URL: one per shop\n\nEvery shop is its own server: `https://{shopDomain}`. The REST base is `https://{shopDomain}/ucp/v1`, the business profile `https://{shopDomain}/.well-known/ucp`. Use the `endpoint` the profile publishes rather than building the URL yourself.\n\nA domain serves UCP only when **all** of these hold: it is a custom domain of the shop with verified DNS and an active TLS certificate, the merchant switched UCP on for that shop, the shop’s built-in storefront is on, its storefront key is active and unexpired, and the company’s e-shop module is on. Otherwise every UCP URL on that host answers `404 {\"code\":\"not_found\",\"content\":\"No UCP business on this host\"}` — the same answer in every case, on purpose. A domain that has no certificate of its own yet does not get that far: the TLS handshake fails before any HTTP answer, because the web server then presents a Monokaido certificate that does not name the domain. Monokaido’s own `*.shop.monokaido.com` subdomains never serve UCP. A deactivated or billing-locked company answers `503 service_unavailable` on every request.\n\nThe shop is picked from the request’s `Host` header alone (no API key, no cookie, no OAuth). Every URL the API publishes — the profile `endpoint`, `continue_url`, `order.permalink_url`, product URLs — uses the shop’s **primary** verified domain, which can differ from the domain you called. Plain `http://` is redirected (301) to `https://` by the web server; send `https://` from the start.\n\n## Before the first call: your platform profile\n\nEvery `/ucp/v1/*` request must carry `UCP-Agent: profile=\"https://…\"` naming **your** platform profile — a JSON document you host. The shop fetches it (HTTPS, no redirects, HTTP 200 only, at most 256 KiB, 5 s), requires `ucp.version` to be exactly `2026-04-08`, and intersects the capabilities you declare with its own. A minimal profile that unlocks everything:\n\n```json\n{\n  \"ucp\": {\n    \"version\": \"2026-04-08\",\n    \"capabilities\": {\n      \"dev.ucp.shopping.catalog.search\": [{ \"version\": \"2026-04-08\" }],\n      \"dev.ucp.shopping.catalog.lookup\": [{ \"version\": \"2026-04-08\" }],\n      \"dev.ucp.shopping.cart\": [{ \"version\": \"2026-04-08\" }],\n      \"dev.ucp.shopping.checkout\": [{ \"version\": \"2026-04-08\" }],\n      \"dev.ucp.shopping.fulfillment\": [{ \"version\": \"2026-04-08\" }],\n      \"dev.ucp.shopping.discount\": [{ \"version\": \"2026-04-08\" }]\n    }\n  }\n}\n```\n\nServe it with `Cache-Control: public, max-age=3600`: the shop caches it for that long (clamped to 60 s – 1 h, 5 min without a `max-age`). Details are on the `UCP-Agent` parameter.\n\n## Negotiation and the ucp envelope\n\nEach operation needs one **root capability**, named by `x-ucp-capability` on the operation: `catalog.search` for search, `catalog.lookup` for lookup and product, `cart` for every `/carts` route, `checkout` for every `/checkout-sessions` route. Extensions apply only when negotiated: `dev.ucp.shopping.fulfillment` (shipping on checkouts) and `dev.ucp.shopping.discount` (codes on carts and checkouts). Fields of an extension you did not negotiate are ignored.\n\nEvery JSON answer of `/.well-known/ucp` and `/ucp/v1/*` except a protocol error carries a top-level `ucp` object with `version`. On `/ucp/v1/*` it also holds `status: \"error\"` only on a business error, `capabilities` (the root and its negotiated extensions; `{}` in a `capabilities_incompatible` answer) and `payment_handlers: {}` on checkout answers that are not errors. The business profile’s `ucp` object lists the shop’s services, all its capabilities and `payment_handlers: {}`. When the root capability is not negotiated — including every cart and checkout call on a shop in catalog mode — the answer is **HTTP 200** with the `capabilities_incompatible` message, and nothing runs.\n\n## Errors versus messages\n\n* **Protocol error** — the request could not be processed: a non-2xx status with `{\"code\",\"content\",\"continue_url\"?}` and no `ucp` object (`Error`).\n* **Business outcome** — HTTP 200 (201 for a created cart or checkout) with `messages[]`. If no resource could be returned the body is `{\"ucp\":{…,\"status\":\"error\"},\"messages\":[…],\"continue_url\"}` (`UcpBusinessErrorResponse`). An unknown cart, checkout or product — and a canceled or expired cart — is such a 200 `not_found`, never an HTTP 404 (a canceled or expired checkout is returned with `status: \"canceled\"`).\n* **Not from the API** — the web server in front answers some requests itself with an **HTML** page: 413 for a body over 1 MiB, 429 above 100 requests/s per client IP (burst 200), 502/504 when the API is down or slow.\n\nEvery code and what to do about it: [Errors and messages](https://help.monokaido.com/en/ucp/errors).\n\n## Idempotency and concurrency\n\n`Idempotency-Key` is **optional** but strongly recommended on the seven writes: without it a retried create makes a second session. A key is scoped to the shop and your exact profile URL, kept at least 25 h, and replays the stored answer. Writes and checkout reads on one session are serialised; a request that cannot get its turn within 10 s (or finds 4 already waiting) gets `503` with `Retry-After: 1` — retry it with the same key. See [Idempotency, concurrency and limits](https://help.monokaido.com/en/ucp/reliability).\n\n## Rate limits and caps\n\nPer client IP and per operation, per minute: 600 for reads (profile, catalog, `GET` cart / checkout), 300 for writes, 60 for the handoff routes; over it, `429 rate_limited` with `Retry-After: 60`. A count does not always fall back 60 s after a request (see `X-RateLimit-Remaining`): keep steady traffic at half a limit or less. The buckets are keyed by client IP and operation, not by shop, so one egress IP shares them across every Monokaido shop. The web server adds 100 requests/s per client IP (burst 200): one budget for everything that IP sends to any shop host Monokaido serves (pages and images included) and to the storefront API, not per shop. Request caps: 100 line items, quantity 999 per line (silently lowered), 10 discount codes, 20 lookup ids, search page size 20 (silently lowered), body 1 MiB as sent and 2 MiB once decompressed (a form-encoded body 100 KiB and 1 000 fields).\n\n## Money and language\n\nAmounts are integers in ISO 4217 **minor units** of the currency next to them (`69900` EUR = 699.00 €; HUF also has two decimals: 1 990 Ft = `199000`), VAT-inclusive, and already include the shop’s markup rules. The language comes from `context.language`, else `Accept-Language`, else the shop’s first language; it decides the currency and the translations. `context.currency` never changes the currency of the prices.\n\n## Caching\n\nEvery answer is `Cache-Control: no-store`, except the business profile (`public, max-age=300`). Responses also carry an `ETag`: strong as the API sends it, weak (`W/\"…\"`) when the web server compresses the answer, which it does for a client that sends `Accept-Encoding: gzip`. Either form works in `If-None-Match`.\n\n## Transport notes\n\n* HTTPS only. Send request bodies as `Content-Type: application/json` (exactly that media type — `application/*+json` is not read) in UTF-8. The API reads a JSON body up to 2 MiB once decompressed; the web server refuses a body over 1 MiB as sent before that.\n* The API also parses `application/x-www-form-urlencoded` bodies (nested `a[b]=…` keys; every value arrives as a string, so numeric fields such as `quantity` or `pagination.limit` are refused; at most 100 KiB once decompressed and 1 000 fields, above that `413 request_too_large`). Do not rely on it. A body of any other content type is not read at all: the operation then sees no body — `400 invalid_request` `request must be an object` where a body is required, and a search with no parameters (every listed product) for `POST /ucp/v1/catalog/search`.\n* Bodies are parsed before routing: a body sent as JSON that does not parse is `400 invalid_request` \"The request is not valid\" on every route, including those that ignore their body (the cancel routes).\n* JSON object key order is not significant. Answers built from stored data (an idempotent replay, a read of a session, a closed or handed-over session) come back with their keys in PostgreSQL JSONB order — shorter keys first, then alphabetically — while a freshly built answer has another order. Compare and parse by key, never by position.\n* Call from a server: there is no CORS for third-party origins, so a browser page on another origin cannot call this API.\n* No request id is returned; log your own correlation id. An `X-Request-ID` header you send is logged by the web server with the request and passed on to the API — quote it when you contact support.\n* A write that carries a Monokaido session cookie (`accessToken`, `refreshToken`, `platformAccessToken`, `platformRefreshToken`) and comes from a foreign web origin is refused with `403 invalid_request` by the platform’s cross-origin write gate. A server-side agent sends neither.\n\n## Manual\n\n* [Agentic commerce (UCP) — overview](https://help.monokaido.com/en/ucp)\n* [Developer quickstart](https://help.monokaido.com/en/ucp/quickstart) — a whole purchase with curl, JavaScript and Python\n* [Concepts and lifecycle](https://help.monokaido.com/en/ucp/concepts)\n* [API reference](https://help.monokaido.com/en/ucp/api-reference)\n* [Errors and messages](https://help.monokaido.com/en/ucp/errors)\n* [Idempotency, concurrency and limits](https://help.monokaido.com/en/ucp/reliability)\n* [Security and data protection](https://help.monokaido.com/en/ucp/security)\n* [For AI agents](https://help.monokaido.com/en/ucp/ai-agents) — tool definitions and agent rules\n* [UCP conformance](https://help.monokaido.com/en/ucp/conformance)\n* [UCP FAQ](https://help.monokaido.com/en/ucp/faq)\n* [Turning UCP on for a shop](https://help.monokaido.com/en/ucp/merchant-setup) — for merchants\n\nMachine-readable: this document as [JSON](https://help.monokaido.com/ucp/openapi.json) and [YAML](https://help.monokaido.com/ucp/openapi.yaml), [function-calling tools](https://help.monokaido.com/ucp/tools.json), [llms-full.txt](https://help.monokaido.com/ucp/llms-full.txt).",
    "contact": {
      "name": "Monokaido Support",
      "url": "https://monokaido.com",
      "email": "support@monokaido.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://monokaido.com/terms"
    }
  },
  "externalDocs": {
    "description": "Agentic commerce (UCP) — the Monokaido manual",
    "url": "https://help.monokaido.com/en/ucp"
  },
  "servers": [
    {
      "url": "https://{shopDomain}",
      "description": "One shop: a custom domain of a Monokaido shop with UCP switched on (use the host of the endpoint in its /.well-known/ucp)",
      "variables": {
        "shopDomain": {
          "default": "shop.example.com",
          "description": "The shop’s custom domain, lower-case, without a port (e.g. `shop.example.com`). `*.shop.monokaido.com` subdomains never serve UCP."
        }
      }
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Discovery",
      "description": "The business profile at `/.well-known/ucp`: the protocol version, the REST endpoint and the capabilities this shop declares. Needs no `UCP-Agent` header."
    },
    {
      "name": "Catalog",
      "description": "Search, lookup and product detail over the shop’s catalog — the same products, prices and stock states the shop’s own pages show. Search reads the shop’s product listing, a materialised view the platform refreshes in the background after catalog changes, so a new or changed product can take a few minutes to show up there; lookup and product read the product data itself. Reads only; no `Idempotency-Key`."
    },
    {
      "name": "Cart",
      "description": "Carts (`dev.ucp.shopping.cart`): a basket priced by the shop, kept 7 days from the last write. A cart can be converted into a checkout (`POST /ucp/v1/checkout-sessions` with `cart_id`) or handed to the buyer directly through its `continue_url` — but only a checkout is ever marked `completed` by the buyer’s order. Carts carry no `status` field."
    },
    {
      "name": "Checkout",
      "description": "Checkout sessions (`dev.ucp.shopping.checkout`, with the `fulfillment` and `discount` extensions): buyer, shipping address and option, codes. Status `incomplete` → `requires_escalation` (ready; the buyer pays on the shop) → `completed` (the buyer placed the order) or `canceled`. Kept 24 h from the last write."
    },
    {
      "name": "Buyer handoff",
      "description": "`continue_url` (`https://{shopDomain}/ucp/continue/{token}`) is opened by the **buyer’s browser**, never by an agent. The page posts to the same URL from the buyer’s browser, which adds the session’s lines and discount code to the shop cart that browser shows and continues to `/checkout` or `/cart` (`/` on a shop in catalog mode). These two routes are documented for completeness and for platforms that render the link; agents must never call them.",
      "x-audience": "buyer-browser"
    }
  ],
  "paths": {
    "/.well-known/ucp": {
      "get": {
        "operationId": "getBusinessProfile",
        "tags": [
          "Discovery"
        ],
        "summary": "Get the business profile",
        "description": "The shop’s UCP business profile: protocol version, the REST `endpoint` to call, the capabilities it declares and `payment_handlers: {}`. Fetch it first and use its `endpoint` (on the shop’s primary domain). Needs no `UCP-Agent` header and no negotiation.\n\n* Cacheable: `Cache-Control: public, max-age=300` (every other UCP answer is `no-store`). Never redirected.\n* A shop in catalog mode declares only `dev.ucp.shopping.catalog.search` and `dev.ucp.shopping.catalog.lookup`.\n* No `supported_versions` (one version only), no `signing_keys` (no webhooks are sent, responses are not signed).\n* The web server maps this path to the API’s `/ucp/well-known`, which answers the same. `/.well-known/ucp/` (trailing slash) is not this route.\n\nMerchant checks: [Turning UCP on for a shop](https://help.monokaido.com/en/ucp/merchant-setup).",
        "x-ucp-capability": null,
        "x-rate-limit": {
          "limit": 600,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "responses": {
          "200": {
            "description": "The business profile.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlProfile"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessProfile"
                },
                "examples": {
                  "BusinessProfile": {
                    "$ref": "#/components/examples/BusinessProfile"
                  },
                  "BusinessProfileCatalogMode": {
                    "$ref": "#/components/examples/BusinessProfileCatalogMode"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ShopUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/catalog/search": {
      "post": {
        "operationId": "searchCatalog",
        "tags": [
          "Catalog"
        ],
        "summary": "Search the catalog",
        "description": "Full-text search over the products the shop lists, with paging and an optional price filter.\n\n* **Matching**: `query` is a case-insensitive, diacritic-sensitive (`modra` does not find `Modrá`) substring of the product title in the answer’s language, or of the product code / external ids. Descriptions, brand names, variant SKUs and GTINs are not searched — use `lookupCatalog` for SKUs and ids.\n* **Order**: newest product first. There is no relevance ranking and no sort option.\n* **What is listed**: published, enabled, listed and orderable products the storefront shows (its exclusion filters and blocked categories apply). A product without a priced variant, or with no variant inside the price filter, is dropped after the page is read, so a page can be short — even empty while `has_next_page` is true. Keep following `cursor` until `has_next_page` is false.\n* **Paging**: `pagination.limit` default 10, at most 20 (larger values are lowered). The cursor encodes only the page number; repeat the query, filters, limit and context with it. `total_count` is the number of matching listed products and is left out whenever a price filter is in effect. Pages are counted over a listing that can change while you page (a product published meanwhile shifts the later pages): de-duplicate products by `id`.\n* **Prices**: in the currency of the answer’s language; `filters.price` is in `context.currency` (see `PriceFilter`). Search reads the shop’s product listing, a materialised view refreshed in the background after catalog changes: a new or changed product can take a few minutes to show here (lookup and product read the product data itself).\n* **Categories**: not supported; a non-empty `filters.categories` → 400.\n\nAn absent body — or one of a content type the API does not parse (anything but `application/json` and `application/x-www-form-urlencoded`) — is an empty search.",
        "x-ucp-capability": "dev.ucp.shopping.catalog.search",
        "x-ucp-operation": "search_catalog",
        "x-rate-limit": {
          "limit": 600,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional. No body lists every product, newest first.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogSearchRequest"
              },
              "examples": {
                "firstPage": {
                  "$ref": "#/components/examples/CatalogSearchRequest"
                },
                "nextPage": {
                  "$ref": "#/components/examples/CatalogSearchNextPageRequest"
                },
                "priceFilter": {
                  "$ref": "#/components/examples/CatalogSearchPriceFilterRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A page of results (`CatalogSearchResponse`), or — when your profile does not declare `dev.ucp.shopping.catalog.search` — the `capabilities_incompatible` business error.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/CatalogSearchResponse"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "firstPage": {
                    "$ref": "#/components/examples/CatalogSearchResponse"
                  },
                  "priceFilter": {
                    "$ref": "#/components/examples/CatalogSearchPriceFilterIgnored"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  For this operation: `request must be an object` (a JSON body that is not an object), `request.query must be a string`, `filters must be an object`, `filters.price must be an object`, `filters.price.min|max must be a non-negative integer`, `filters.categories must be an array of strings`, `filters.categories is not supported by this shop; search by query (and filters.price) instead`, `pagination must be an object`, `pagination.limit must be a positive integer` (also `null`), `pagination.cursor is not valid`, `context must be an object`, `context.<field> must be a string`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorSearchCategories": {
                    "$ref": "#/components/examples/ErrorSearchCategories"
                  },
                  "ErrorSearchCursor": {
                    "$ref": "#/components/examples/ErrorSearchCursor"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/catalog/lookup": {
      "post": {
        "operationId": "lookupCatalog",
        "tags": [
          "Catalog"
        ],
        "summary": "Look products up by identifier",
        "description": "Up to 20 identifiers in one call — variant ids, variant SKUs, product ids, product handles — answered from the product data itself, not from the search listing.\n\n* A variant id or SKU matches that variant (`inputs[].match: \"exact\"`); a SKU can match variants of several products. A product id or handle (in any language) matches the product’s featured variant (`\"featured\"`). An identifier that matched a variant is not tried as a product.\n* Each product appears once, in the order its first identifier appears in `ids`, and lists **only the variants that were asked for**; its `price_range`, `list_price_range` and `options` still describe all its priced variants (within the price filter, when one is set).\n* Every identifier that matched nothing — unknown, hidden by the shop, or the asked variant has no price — gets an `info` `not_found` message whose `content` is the identifier.\n* Unlike search, a product the shop does not list in its catalog pages (but would show by its URL) is found, and a product that is not orderable is returned with every variant `discontinued`.\n* `filters.price` works as in search; an asked variant outside it is reported `not_found`.",
        "x-ucp-capability": "dev.ucp.shopping.catalog.lookup",
        "x-ucp-operation": "lookup_catalog",
        "x-rate-limit": {
          "limit": 600,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The identifiers.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CatalogLookupRequest"
              },
              "examples": {
                "CatalogLookupRequest": {
                  "$ref": "#/components/examples/CatalogLookupRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The products found (`CatalogLookupResponse`) — HTTP 200 also when none was — or the `capabilities_incompatible` business error.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/CatalogLookupResponse"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CatalogLookupResponse": {
                    "$ref": "#/components/examples/CatalogLookupResponse"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  For this operation: `request must be an object` (also for no body), `ids must be a non-empty array`, and the price / category filter refusals of search.\n* `request_too_large` \"ids holds at most 20 identifiers\" — more than 20 entries in `ids` (HTTP 400, not 413).",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorLookupNoIds": {
                    "$ref": "#/components/examples/ErrorLookupNoIds"
                  },
                  "ErrorLookupTooManyIds": {
                    "$ref": "#/components/examples/ErrorLookupTooManyIds"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/catalog/product": {
      "post": {
        "operationId": "getProduct",
        "tags": [
          "Catalog"
        ],
        "summary": "Get one product in detail",
        "description": "One product with all its priced variants and, for each option value, whether it exists and is available next to the current selection. Use it to drive a variant picker.\n\n* `id` may be a product id, a product handle or a variant id (SKUs are not accepted here).\n* The anchor variant is chosen by `selected` (all selections must match; when none does, selections are dropped from the end); else the variant named by `id`; else the featured variant. It comes first in `variants`, and `selected` in the answer repeats its options.\n* `filters.price` and `preferences` are ignored. Relaxed selections are not reported.\n* An unknown or hidden product is a 200 business error `not_found`, not an HTTP 404. This operation needs `dev.ucp.shopping.catalog.lookup` (there is no separate capability).",
        "x-ucp-capability": "dev.ucp.shopping.catalog.lookup",
        "x-ucp-operation": "get_product",
        "x-rate-limit": {
          "limit": 600,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The product and an optional selection.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetProductRequest"
              },
              "examples": {
                "GetProductRequest": {
                  "$ref": "#/components/examples/GetProductRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The product (`GetProductResponse`), or a business error: `not_found` (unknown or hidden product) or `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GetProductResponse"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "GetProductResponse": {
                    "$ref": "#/components/examples/GetProductResponse"
                  },
                  "ProductNotFound": {
                    "$ref": "#/components/examples/ProductNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  For this operation: `request must be an object` (also for no body), `id is required`, the category filter refusal.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorProductIdRequired": {
                    "$ref": "#/components/examples/ErrorProductIdRequired"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/carts": {
      "post": {
        "operationId": "createCart",
        "tags": [
          "Cart"
        ],
        "summary": "Create a cart",
        "description": "Creates a cart priced by the shop: the shop’s own prices, VAT, markup rules and stock, in the currency of the session’s language.\n\n* Answers **201** with the cart. Lines that cannot be bought are left out with a message (`item_unavailable`, `out_of_stock`, `vat_mix_not_allowed`); a quantity above the sellable stock is lowered with `quantity_adjusted`. A line’s quantity above 999 is lowered to 999 without a message; lines of one item that add up to more than 999 are lowered with `quantity_adjusted`. `line_items: []` creates an empty cart.\n* If lines were sent and **none** could be added, no cart is created: HTTP 200 business error `out_of_stock` (all sold out) or `item_unavailable`.\n* With `dev.ucp.shopping.discount` the codes are applied (one at a time, see `DiscountsRequest`) and the answer has `discounts`.\n* The cart lives 7 days from its last write. It has a `continue_url` you can give the buyer — but only a **checkout** is ever marked `completed` by the buyer’s order, so convert the cart first if you want to follow the outcome.\n* Send an `Idempotency-Key`: a retried create without one makes a second cart.",
        "x-ucp-capability": "dev.ucp.shopping.cart",
        "x-ucp-operation": "create_cart",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "create_cart",
          "target": "\"\"",
          "body": "the request body"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CartCreateRequest"
              },
              "examples": {
                "create": {
                  "$ref": "#/components/examples/CartCreateRequest"
                },
                "soldOut": {
                  "$ref": "#/components/examples/CartCreateSoldOutRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "No cart: none of the requested items could be added, or `capabilities_incompatible` (always a business error; typed as the union of the other cart answers so that generated clients read the 201 cart correctly).",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Cart"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "soldOut": {
                    "$ref": "#/components/examples/CartAllUnavailable"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "201": {
            "description": "The cart was created.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                },
                "examples": {
                  "create": {
                    "$ref": "#/components/examples/CartCreated"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  For this operation: `request must be an object` (also for no body), `line_items must be an array`, `line_items holds at most 100 entries`, `line_items[i] must be an object`, `line_items[i].item must be an object`, `line_items[i].item.id is required`, `line_items[i].quantity must be a positive integer`, `buyer must be an object`, `buyer.<field> must be a string`, `context …`, `discounts.codes must be an array`, `discounts.codes holds at most 10 codes`, the `fulfillment …` refusals. Nothing is stored.\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorInvalidRequest": {
                    "$ref": "#/components/examples/ErrorInvalidRequest"
                  },
                  "ErrorLineItemsRequired": {
                    "$ref": "#/components/examples/ErrorLineItemsRequired"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/carts/{id}": {
      "get": {
        "operationId": "getCart",
        "tags": [
          "Cart"
        ],
        "summary": "Get a cart",
        "description": "The cart as it is now. A read stores nothing, does not extend `expires_at`, and carries no line or discount messages (those come only with the write that caused them). Each line keeps the unit price it got when its variant entered the cart (or was re-added for a new language), unless the storefront has **Live prices on cart load** switched on (not visible through UCP): then every read and write prices the lines again.\n\n* An unknown, canceled or expired cart is a 200 business error `not_found`.\n* After the buyer took the cart to the shop (its `continue_url` page added the lines to the buyer’s shop cart), the last answer is returned again — its messages included — with a fresh `ucp` object; nothing on it says so. Line and discount messages of the write that produced that answer come back on every read: do not report them to the buyer again, and do not take them for a sign of the handoff.\n* This read does not wait for a write in progress on the same cart.",
        "x-ucp-capability": "dev.ucp.shopping.cart",
        "x-ucp-operation": "get_cart",
        "x-rate-limit": {
          "limit": 600,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CartId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "description": "The cart, or a business error: `not_found` or `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Cart"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CartRetrieved": {
                    "$ref": "#/components/examples/CartRetrieved"
                  },
                  "CartNotFound": {
                    "$ref": "#/components/examples/CartNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      },
      "put": {
        "operationId": "updateCart",
        "tags": [
          "Cart"
        ],
        "summary": "Update a cart",
        "description": "Replaces the cart’s lines and, when sent, its buyer, context and discount codes; fields you leave out keep their value. `line_items` is **required** and is a full replacement (a line you do not list is removed).\n\n* Every successful write extends `expires_at` to now + 7 days.\n* `buyer` replaces the whole stored buyer (a field you leave out is erased); `null` clears it.\n* A `context.language` different from the stored one that picks another shop language re-adds every line in it (its currency, new line ids).\n* After the buyer took the cart to the shop, a PUT changes nothing: the last answer comes back with a `handed_off` warning (no validation of the body’s lines either).\n* Requests on one cart are serialised (see 503).",
        "x-ucp-capability": "dev.ucp.shopping.cart",
        "x-ucp-operation": "update_cart",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "update_cart",
          "target": "the path {id} as sent",
          "body": "the request body"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CartId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CartUpdateRequest"
              },
              "examples": {
                "CartUpdateRequest": {
                  "$ref": "#/components/examples/CartUpdateRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated cart (`messages` lists what was adjusted or refused); the unchanged cart with `handed_off` after a handoff; or a business error: `not_found`, `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Cart"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CartUpdated": {
                    "$ref": "#/components/examples/CartUpdated"
                  },
                  "CartUpdateHandedOff": {
                    "$ref": "#/components/examples/CartUpdateHandedOff"
                  },
                  "CartNotFound": {
                    "$ref": "#/components/examples/CartNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  As for `createCart`; `line_items` missing → `line_items must be an array`. The cart is not changed.\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorLineItemsRequired": {
                    "$ref": "#/components/examples/ErrorLineItemsRequired"
                  },
                  "ErrorInvalidRequest": {
                    "$ref": "#/components/examples/ErrorInvalidRequest"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/carts/{id}/cancel": {
      "post": {
        "operationId": "cancelCart",
        "tags": [
          "Cart"
        ],
        "summary": "Cancel a cart",
        "description": "Cancels the cart. The answer is the cart as it was — with `continue_url` and the stored `expires_at`, because a cart has no `status`. From then on every operation on it answers `not_found`, and its `continue_url` shows the “gone” page.\n\n* Any request body is ignored (the Idempotency-Key hashes `{}`).\n* Canceling a cart does not cancel a checkout made from it.",
        "x-ucp-capability": "dev.ucp.shopping.cart",
        "x-ucp-operation": "cancel_cart",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "cancel_cart",
          "target": "the path {id} as sent",
          "body": "{} (the body is ignored)"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CartId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "description": "The cart as it was when canceled, or a business error: `not_found` (unknown, already canceled or expired), `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Cart"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CartCanceled": {
                    "$ref": "#/components/examples/CartCanceled"
                  },
                  "CartNotFound": {
                    "$ref": "#/components/examples/CartNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` \"The request is not valid\" — a body sent as JSON that does not parse (the body is ignored, but it is parsed before routing);\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/checkout-sessions": {
      "post": {
        "operationId": "createCheckout",
        "tags": [
          "Checkout"
        ],
        "summary": "Create a checkout session",
        "description": "Creates a checkout session — directly from `line_items`, or by converting a cart (`cart_id`, when `dev.ucp.shopping.cart` is negotiated).\n\n* A new checkout answers **201**. Its `status` is `incomplete` while anything the platform can provide is missing (every gap is a `recoverable` error with a `path`) or this write refused a line (`item_unavailable`, `out_of_stock`, `vat_mix_not_allowed` are `recoverable` errors too, without a `path` when the line is not in the answer; the next read no longer repeats them), else `requires_escalation` with `payment_required`.\n* **Ready** needs: at least one line, a valid `buyer.email`, and — with `dev.ucp.shopping.fulfillment` — a destination with street, city, postal code and a recognised country that the shop ships to, plus a `selected_option_id` among the offered options. Names and phone are optional. A Packeta option adds `pickup_point_required` (chosen by the buyer on the shop) but does not block readiness.\n* **From a cart**: lines, buyer, context and language come from the cart (this request’s `line_items`, `buyer` and `context` are ignored; `buyer` and `context` are still checked); `fulfillment` from this request; discount codes from this request when sent, else the cart’s. The checkout gets its own lines (new line ids); the cart is left as it was. A cart has at most one open checkout: converting it again answers that checkout with **200** and applies nothing from the request (update the checkout instead). A cart the buyer already took to the shop → 200 `handed_off`.\n* If the cart’s open checkout has expired, it is canceled and a new one is created (201).\n* If lines were sent and none could be added, no checkout is created (200 `out_of_stock` / `item_unavailable`).\n* The checkout lives 24 h from its last write. Send an `Idempotency-Key`: a retried create without one makes a second checkout.",
        "x-ucp-capability": "dev.ucp.shopping.checkout",
        "x-ucp-operation": "create_checkout",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "create_checkout",
          "target": "\"\"",
          "body": "the request body"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutCreateRequest"
              },
              "examples": {
                "fromCart": {
                  "$ref": "#/components/examples/CheckoutFromCartRequest"
                },
                "direct": {
                  "$ref": "#/components/examples/CheckoutCreateRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The cart’s existing open checkout (nothing from this request applied), or a business error: `handed_off`, `not_found` (unknown `cart_id`, reported as \"Checkout session not found\"), `out_of_stock` / `item_unavailable` (nothing could be added), `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Checkout"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CheckoutExistingForCart": {
                    "$ref": "#/components/examples/CheckoutExistingForCart"
                  },
                  "CheckoutFromHandedOffCart": {
                    "$ref": "#/components/examples/CheckoutFromHandedOffCart"
                  },
                  "CheckoutNotFound": {
                    "$ref": "#/components/examples/CheckoutNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "201": {
            "description": "A new checkout session.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                },
                "examples": {
                  "fromCart": {
                    "$ref": "#/components/examples/CheckoutIncomplete"
                  },
                  "direct": {
                    "$ref": "#/components/examples/CheckoutCreatedDirect"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  For this operation: as for `createCart` (without a usable `cart_id`, `line_items` is required), plus `fulfillment must be an object`, `fulfillment.methods must be an array`, `fulfillment.methods[i] must be an object`, `fulfillment.methods[].destinations must be an array`, `fulfillment.methods[].destinations[i] must be an object`, `fulfillment.methods[].groups[0] must be an object`, `fulfillment.methods[].destinations[i].address_country is not a recognised country; send an ISO 3166-1 alpha-2 code such as \"SK\"`. Nothing is stored.\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorInvalidRequest": {
                    "$ref": "#/components/examples/ErrorInvalidRequest"
                  },
                  "ErrorUnknownCountry": {
                    "$ref": "#/components/examples/ErrorUnknownCountry"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/checkout-sessions/{id}": {
      "get": {
        "operationId": "getCheckout",
        "tags": [
          "Checkout"
        ],
        "summary": "Get a checkout session",
        "description": "The checkout as it is now. Poll this to learn the outcome after giving the buyer `continue_url`: stop at `status: \"completed\"` (read `order`) or `\"canceled\"`.\n\n* An open checkout is read again from its backing cart: its status is re-derived (`incomplete` ⇄ `requires_escalation`), the shipping options are quoted again, and the answer is stored. So a GET waits for writes on the same session and **can answer 503** with `Retry-After: 1`. Keep one request per session in flight; poll every few seconds, not faster.\n* A read leaves the lines and the codes alone: no stock check, no code applied again, and each line keeps its unit price — unless the storefront has **Live prices on cart load** switched on (not visible through UCP), which prices the lines again on every read and write.\n* A GET does not extend `expires_at`. The first request on an open checkout at or after `expires_at` (a read, a write, or a conversion of its cart) turns it `canceled` for good; an order placed before that request still completes it.\n* Line and discount messages are not repeated on a read.\n* A completed or canceled checkout returns the last answer it gave, with the current `status`, `messages: []`, no `continue_url` and, once completed, `order`. An open one the buyer already took to the shop returns its last answer as it was (messages included: the line and discount messages of the write that produced it come back on every read — do not report them again). Neither is re-priced. A GET cannot tell whether the buyer opened the link.\n* An unknown id is a 200 business error `not_found`.",
        "x-ucp-capability": "dev.ucp.shopping.checkout",
        "x-ucp-operation": "get_checkout",
        "x-rate-limit": {
          "limit": 600,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "description": "The checkout (any status), or a business error: `not_found`, `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Checkout"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CheckoutRequiresEscalation": {
                    "$ref": "#/components/examples/CheckoutRequiresEscalation"
                  },
                  "CheckoutExistingForCart": {
                    "$ref": "#/components/examples/CheckoutExistingForCart"
                  },
                  "CheckoutCompleted": {
                    "$ref": "#/components/examples/CheckoutCompleted"
                  },
                  "CheckoutCanceled": {
                    "$ref": "#/components/examples/CheckoutCanceled"
                  },
                  "CheckoutNotFound": {
                    "$ref": "#/components/examples/CheckoutNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      },
      "put": {
        "operationId": "updateCheckout",
        "tags": [
          "Checkout"
        ],
        "summary": "Update a checkout session",
        "description": "Sets the buyer, the shipping destination and option, discount codes or the lines; fields you leave out keep their value. Answers the checkout with its status re-derived, the shipping options quoted again and, with the discount extension, the codes applied again.\n\n* `line_items` (optional) is a full replacement, checked like a create (stock, availability, the quantity caps); without it the lines are not checked again. `buyer` replaces the whole stored buyer. A destination can be replaced but not removed. `selected_option_id: null` clears the shipping choice.\n* A line keeps the unit price it got when its variant entered the session, also when its quantity changes. A new `context.language` re-adds every line at that language’s current prices. A storefront with **Live prices on cart load** on (not visible through UCP) prices the lines again on every read and write; elsewhere a checkout kept open by updates keeps its old prices — leave a line out of one update and send it again in the next to price it anew.\n* Every update of an open checkout extends `expires_at` to now + 24 h — also `{}`.\n* On a completed or canceled checkout nothing changes: it comes back with `checkout_completed` / `checkout_canceled`.\n* After the buyer opened `continue_url` (but before the order), nothing changes: the last answer comes back with a `handed_off` warning.\n* On an unknown, closed or handed-over checkout the body’s fields are not read (only a body that is not an object is refused): such a 200 says nothing about whether the body was valid.",
        "x-ucp-capability": "dev.ucp.shopping.checkout",
        "x-ucp-operation": "update_checkout",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "update_checkout",
          "target": "the path {id} as sent",
          "body": "the request body"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutUpdateRequest"
              },
              "examples": {
                "CheckoutUpdateRequest": {
                  "$ref": "#/components/examples/CheckoutUpdateRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The checkout after the update; the unchanged checkout with `handed_off`, `checkout_completed` or `checkout_canceled`; or a business error: `not_found`, `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Checkout"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CheckoutRequiresEscalation": {
                    "$ref": "#/components/examples/CheckoutRequiresEscalation"
                  },
                  "CheckoutUpdateHandedOff": {
                    "$ref": "#/components/examples/CheckoutUpdateHandedOff"
                  },
                  "CheckoutAlreadyCompleted": {
                    "$ref": "#/components/examples/CheckoutAlreadyCompleted"
                  },
                  "CheckoutNotFound": {
                    "$ref": "#/components/examples/CheckoutNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` — a field this operation reads has the wrong JSON type or value; `content` names it. Malformed JSON or a top-level JSON primitive says only \"The request is not valid\". Unknown fields are ignored, never refused.\n  As for `createCheckout`. The checkout is not changed.\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorUnknownCountry": {
                    "$ref": "#/components/examples/ErrorUnknownCountry"
                  },
                  "ErrorInvalidRequest": {
                    "$ref": "#/components/examples/ErrorInvalidRequest"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/checkout-sessions/{id}/complete": {
      "post": {
        "operationId": "completeCheckout",
        "tags": [
          "Checkout"
        ],
        "summary": "Complete a checkout session (no payment, no order)",
        "description": "**Never places an order and never takes a payment.** UCP’s complete step is answered with the checkout as it stands: `requires_escalation` with `payment_required` and `continue_url` once it is ready (`incomplete` with its gaps otherwise), or `completed` with `order` once the buyer has ordered on the shop. It never makes a checkout `completed`: like `getCheckout` it re-derives `incomplete` ⇄ `requires_escalation` of an open checkout from what is stored (the shipping options quoted again, the lines and codes not checked again) and stores that answer, and it does not extend `expires_at`.\n\nTo finish a purchase, give `continue_url` to the buyer and poll `getCheckout`. Any `payment` data in the body is ignored and not stored.",
        "x-ucp-capability": "dev.ucp.shopping.checkout",
        "x-ucp-operation": "complete_checkout",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "complete_checkout",
          "target": "the path {id} as sent",
          "body": "the request body (hashed, otherwise ignored)"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Ignored.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutCompleteRequest"
              },
              "examples": {
                "CheckoutCompleteRequest": {
                  "$ref": "#/components/examples/CheckoutCompleteRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The checkout as it stands (a canceled one with `checkout_canceled`), or a business error: `not_found`, `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Checkout"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CheckoutCompleteResponse": {
                    "$ref": "#/components/examples/CheckoutCompleteResponse"
                  },
                  "CheckoutCompleted": {
                    "$ref": "#/components/examples/CheckoutCompleted"
                  },
                  "CheckoutNotFound": {
                    "$ref": "#/components/examples/CheckoutNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` \"The request is not valid\" — a body sent as JSON that does not parse.\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/v1/checkout-sessions/{id}/cancel": {
      "post": {
        "operationId": "cancelCheckout",
        "tags": [
          "Checkout"
        ],
        "summary": "Cancel a checkout session",
        "description": "Cancels an open checkout: `status: \"canceled\"`, `messages: []`, no `continue_url`, the stored `expires_at`. Its `continue_url` then shows the “gone” page and a later order can no longer complete it.\n\n* A completed checkout is not changed (the order is never canceled through UCP): it comes back with `checkout_completed`. A canceled one comes back with `checkout_canceled`.\n* Any request body is ignored (the Idempotency-Key hashes `{}`).",
        "x-ucp-capability": "dev.ucp.shopping.checkout",
        "x-ucp-operation": "cancel_checkout",
        "x-rate-limit": {
          "limit": 300,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "x-idempotency": {
          "operation": "cancel_checkout",
          "target": "the path {id} as sent",
          "body": "{} (the body is ignored)"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CheckoutId"
          },
          {
            "$ref": "#/components/parameters/UcpAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "description": "The canceled checkout; a closed one with `checkout_completed` / `checkout_canceled`; or a business error: `not_found`, `capabilities_incompatible`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Checkout"
                    },
                    {
                      "$ref": "#/components/schemas/UcpBusinessErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "CheckoutCanceled": {
                    "$ref": "#/components/examples/CheckoutCanceled"
                  },
                  "CheckoutAlreadyCompleted": {
                    "$ref": "#/components/examples/CheckoutAlreadyCompleted"
                  },
                  "CheckoutNotFound": {
                    "$ref": "#/components/examples/CheckoutNotFound"
                  },
                  "ErrorCapabilityMissing": {
                    "$ref": "#/components/examples/ErrorCapabilityMissing"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request (`Error`):\n\n* `invalid_profile_url` — the `UCP-Agent` header is missing or unusable (with `continue_url`);\n* `invalid_request` \"The request is not valid\" — a body sent as JSON that does not parse (the body is ignored, but it is parsed before routing);\n* `invalid_request` \"Idempotency-Key is not valid\" — see `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorMissingAgent": {
                    "$ref": "#/components/examples/ErrorMissingAgent"
                  },
                  "ErrorInvalidIdempotencyKey": {
                    "$ref": "#/components/examples/ErrorInvalidIdempotencyKey"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "$ref": "#/components/responses/NoBusinessOnHost"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ProfileProblem"
          },
          "424": {
            "$ref": "#/components/responses/ProfileUnreachable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailableSession"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/ucp/continue/{token}": {
      "get": {
        "operationId": "getContinuePage",
        "tags": [
          "Buyer handoff"
        ],
        "summary": "The buyer’s handoff page (browser only)",
        "description": "**Opened by the buyer’s browser — agents and platform back-ends must never call this route.** Documented so that platforms rendering `continue_url` know what the buyer will see.\n\nAn HTML page on the shop’s own domain. Its script reads the browser’s storefront guest-cart id (`localStorage[\"sf-cart\"]`, created if missing) and the tab’s storefront sign-in (`sessionStorage[\"sf-auth\"]`), posts them to the same URL, and continues with `location.replace` to the path the claim returns (`/checkout`, `/cart` or `/`); without JavaScript, a link to the fallback path. It retries a 5xx / 429 twice (after 1 s and 2 s), then goes to the fallback.\n\n* Opening the page changes nothing (link previews and prefetchers are harmless); only the page’s own POST adds the lines.\n* It needs JavaScript and the shop’s browser storage. The lines land in the cart of the browser (and storage partition) that opened the link: an in-app browser or WebView keeps a cart of its own. Where storage is blocked they land in a cart no page of the shop shows, and the session is frozen all the same.\n* Works while the session is open (`incomplete` / `requires_escalation` checkout, or a cart) and unexpired; afterwards **410**. A host without UCP answers **404**. Both are HTML.\n* Rate-limit, outage and unexpected errors are answered as UCP **JSON**, not HTML.\n* Headers from the API: `Cache-Control: no-store`, `Referrer-Policy: no-referrer`, `X-Robots-Tag: noindex, nofollow` and a strict `Content-Security-Policy`. The shop’s web server adds its own security headers, among them a second `Referrer-Policy: strict-origin-when-cross-origin`, which a browser applies over the first (the last valid value wins). The page’s `<meta name=\"referrer\" content=\"no-referrer\">` overrides the header again, so no request the page makes carries a `Referer`.\n\nWhat happens on the shop: [Concepts and lifecycle](https://help.monokaido.com/en/ucp/concepts).",
        "x-audience": "buyer-browser",
        "x-ucp-capability": null,
        "x-rate-limit": {
          "limit": 60,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/ContinueToken"
          }
        ],
        "responses": {
          "200": {
            "description": "The handoff page.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Content-Security-Policy": {
                "$ref": "#/components/headers/ContentSecurityPolicy"
              },
              "Referrer-Policy": {
                "$ref": "#/components/headers/ReferrerPolicy"
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "The handoff page."
                },
                "examples": {
                  "HandoffPage": {
                    "$ref": "#/components/examples/HandoffPage"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The host serves no UCP (switched off, domain no longer verified …): an empty “gone” page.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Content-Security-Policy": {
                "$ref": "#/components/headers/ContentSecurityPolicy"
              },
              "Referrer-Policy": {
                "$ref": "#/components/headers/ReferrerPolicy"
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "The “gone” page with an empty shop name."
                },
                "examples": {
                  "HandoffNoBusinessPage": {
                    "$ref": "#/components/examples/HandoffNoBusinessPage"
                  }
                }
              }
            }
          },
          "410": {
            "description": "Gone — unknown or malformed token, or the session is completed, canceled or expired: a page with a link to the shop’s home.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Content-Security-Policy": {
                "$ref": "#/components/headers/ContentSecurityPolicy"
              },
              "Referrer-Policy": {
                "$ref": "#/components/headers/ReferrerPolicy"
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "The “gone” page."
                },
                "examples": {
                  "HandoffGonePage": {
                    "$ref": "#/components/examples/HandoffGonePage"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ShopUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      },
      "post": {
        "operationId": "claimHandoff",
        "tags": [
          "Buyer handoff"
        ],
        "summary": "Claim the handoff (the page’s own request, browser only)",
        "description": "**Opened by the buyer’s browser — agents and platform back-ends must never call this route.** Documented so that platforms rendering `continue_url` know what the buyer will see.\n\nAdds the session’s lines (and its applied discount code) to the shop cart this browser shows — the signed-in customer’s cart when a valid storefront token of this shop is sent as `Authorization: Bearer <token>` (the optional `storefrontCustomerToken` security scheme), else the guest cart named by `sessionId` — through the shop’s normal add-to-cart rules, then names the path to continue to.\n\n* Lines are **added** to what the cart holds (same variant: quantities summed, capped at 999); a line the shop refuses (sold out since, over stock, unpriced) is skipped silently. The browser’s cart is never emptied: when it already holds items in another currency the lines go in that currency, or — if they cannot — nothing is added (redirect `/cart`).\n* Only lines and the code travel; buyer data, address and shipping choice do not. The buyer enters them again on the shop’s checkout.\n* Once per browser cart (or customer) and session state: a reload or a second click adds nothing. Another browser or another customer gets the lines once too. A cart link whose cart has an open checkout hands over that checkout instead.\n* After a successful handoff the session is frozen for the agent (writes answer `handed_off`), and an order placed from that browser cart that contains at least one of the session’s variants completes the checkout.\n* The claim queues behind requests on the same session; when it cannot get its turn the answer is the generic 503 with `Retry-After: 60`.",
        "x-audience": "buyer-browser",
        "x-ucp-capability": null,
        "x-rate-limit": {
          "limit": 60,
          "window_seconds": 60,
          "scope": "client IP × operation, across every Monokaido shop"
        },
        "security": [
          {
            "storefrontCustomerToken": []
          },
          {}
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ContinueToken"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HandoffClaimRequest"
              },
              "examples": {
                "HandoffClaimRequest": {
                  "$ref": "#/components/examples/HandoffClaimRequest"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Where the browser goes next. Also answered, with nothing added, when this browser already claimed this session state, when every line was refused, or on a shop in catalog mode (`/`).",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HandoffClaimResponse"
                },
                "examples": {
                  "HandoffClaimResponse": {
                    "$ref": "#/components/examples/HandoffClaimResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_request` \"The request is not valid\": `sessionId` missing or not acceptable (no JSON body counts as missing), or a body sent as JSON that does not parse.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "HandoffClaimInvalidSession": {
                    "$ref": "#/components/examples/HandoffClaimInvalidSession"
                  },
                  "ErrorMalformedJson": {
                    "$ref": "#/components/examples/ErrorMalformedJson"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/CrossOriginRejected"
          },
          "404": {
            "description": "`not_found`: \"No UCP business on this host\", or \"Not found\" when the token is unknown or malformed or the session can no longer be handed over (completed, canceled, expired).",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorNoBusinessOnHost": {
                    "$ref": "#/components/examples/ErrorNoBusinessOnHost"
                  },
                  "HandoffSessionGone": {
                    "$ref": "#/components/examples/HandoffSessionGone"
                  }
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "description": "`service_unavailable` \"This shop is temporarily unavailable\", `Retry-After: 60`: the session is busy with another request (nothing was added; the page retries), or the company is deactivated / billing-locked, or the shop lookup failed.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControlNoStore"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "ErrorShopUnavailable": {
                    "$ref": "#/components/examples/ErrorShopUnavailable"
                  }
                }
              }
            }
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "UcpVersion": {
        "type": "string",
        "const": "2026-04-08",
        "description": "The UCP protocol version. This shop implements exactly one."
      },
      "CapabilityName": {
        "type": "string",
        "enum": [
          "dev.ucp.shopping.catalog.search",
          "dev.ucp.shopping.catalog.lookup",
          "dev.ucp.shopping.cart",
          "dev.ucp.shopping.checkout",
          "dev.ucp.shopping.fulfillment",
          "dev.ucp.shopping.discount"
        ],
        "description": "A capability this business can declare. `catalog.search`, `catalog.lookup`, `cart` and `checkout` are roots; `fulfillment` extends `checkout`; `discount` extends `checkout` and `cart`."
      },
      "CapabilityVersion": {
        "type": "object",
        "description": "A negotiated capability: only its version.",
        "additionalProperties": false,
        "required": [
          "version"
        ],
        "properties": {
          "version": {
            "$ref": "#/components/schemas/UcpVersion"
          }
        }
      },
      "ResponseCapabilities": {
        "type": "object",
        "description": "The capabilities active for this answer: the operation’s root capability and every negotiated extension of it.\n\n* Catalog search: `dev.ucp.shopping.catalog.search`.\n* Catalog lookup and product: `dev.ucp.shopping.catalog.lookup`.\n* Carts: `dev.ucp.shopping.cart`, plus `dev.ucp.shopping.discount` when negotiated.\n* Checkouts: `dev.ucp.shopping.checkout`, plus `dev.ucp.shopping.fulfillment` and `dev.ucp.shopping.discount` when negotiated.\n\nAn extension your profile did not declare is absent. Empty (`{}`) only in the `capabilities_incompatible` answer.",
        "additionalProperties": false,
        "properties": {
          "dev.ucp.shopping.catalog.search": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityVersion"
            },
            "minItems": 1,
            "maxItems": 1
          },
          "dev.ucp.shopping.catalog.lookup": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityVersion"
            },
            "minItems": 1,
            "maxItems": 1
          },
          "dev.ucp.shopping.cart": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityVersion"
            },
            "minItems": 1,
            "maxItems": 1
          },
          "dev.ucp.shopping.checkout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityVersion"
            },
            "minItems": 1,
            "maxItems": 1
          },
          "dev.ucp.shopping.fulfillment": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityVersion"
            },
            "minItems": 1,
            "maxItems": 1
          },
          "dev.ucp.shopping.discount": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityVersion"
            },
            "minItems": 1,
            "maxItems": 1
          }
        }
      },
      "ResponseMetadata": {
        "type": "object",
        "description": "The `ucp` object of a successful catalog or cart answer. A missing `status` means success.",
        "additionalProperties": false,
        "required": [
          "version",
          "capabilities"
        ],
        "properties": {
          "version": {
            "$ref": "#/components/schemas/UcpVersion"
          },
          "capabilities": {
            "$ref": "#/components/schemas/ResponseCapabilities"
          }
        }
      },
      "CheckoutResponseMetadata": {
        "type": "object",
        "description": "The `ucp` object of every checkout answer that returns a checkout (any status).",
        "additionalProperties": false,
        "required": [
          "version",
          "capabilities",
          "payment_handlers"
        ],
        "properties": {
          "version": {
            "$ref": "#/components/schemas/UcpVersion"
          },
          "capabilities": {
            "$ref": "#/components/schemas/ResponseCapabilities"
          },
          "payment_handlers": {
            "type": "object",
            "maxProperties": 0,
            "description": "Always `{}`: no payment is taken through UCP. The buyer pays on the shop’s own checkout, reached through `continue_url`, with the shop’s own payment methods."
          }
        }
      },
      "ErrorResponseMetadata": {
        "type": "object",
        "description": "The `ucp` object of a business error. Never has `payment_handlers`. `capabilities` is `{}` for `capabilities_incompatible` and lists the operation’s root (and its negotiated extensions) otherwise.",
        "additionalProperties": false,
        "required": [
          "version",
          "status",
          "capabilities"
        ],
        "properties": {
          "version": {
            "$ref": "#/components/schemas/UcpVersion"
          },
          "status": {
            "type": "string",
            "const": "error",
            "description": "Present only on a business error: the body carries no resource."
          },
          "capabilities": {
            "$ref": "#/components/schemas/ResponseCapabilities"
          }
        }
      },
      "MessageError": {
        "type": "object",
        "description": "An error message. Always carries a `severity`.",
        "additionalProperties": false,
        "required": [
          "type",
          "code",
          "content",
          "severity"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "error"
          },
          "code": {
            "type": "string",
            "description": "Machine-readable reason. Codes this shop emits:\n\n* `recoverable` — `missing` (path `$.line_items`, `$.buyer.email`, `$.fulfillment.methods[0].destinations` or `$.fulfillment.methods[0].groups[0].selected_option_id`), `invalid_address`, `address_undeliverable`, `invalid_option`, `item_unavailable`, `out_of_stock`, `vat_mix_not_allowed`. Any of them keeps a checkout `incomplete`.\n* `requires_buyer_input` — `payment_required` (always on a `requires_escalation` checkout), `pickup_point_required` (the selected shipping option needs a pickup point, which the buyer picks on the shop; it does not block `requires_escalation`).\n* `unrecoverable` — `not_found`, `capabilities_incompatible`, `handed_off`, `checkout_completed`, `checkout_canceled`, and `out_of_stock` / `item_unavailable` when a create could add none of the requested items.\n\nTreat an unknown code by its `type` and `severity`."
          },
          "content": {
            "type": "string",
            "description": "A sentence in English for logs and developers. Not localised; do not parse it."
          },
          "path": {
            "type": "string",
            "description": "JSONPath into the RETURNED resource (not the request), e.g. `$.line_items[1].quantity`. Line items are returned in the shop cart’s order, which need not be your order: match lines by `id` or `item.id`, never by position. Absent when the message is about the whole request or about a line that is not in the answer.",
            "pattern": "^\\$"
          },
          "severity": {
            "type": "string",
            "enum": [
              "recoverable",
              "requires_buyer_input",
              "requires_buyer_review",
              "unrecoverable"
            ],
            "description": "`recoverable`: the platform can fix it with another request. `requires_buyer_input`: only the buyer can, on the shop (through `continue_url`). `unrecoverable`: retrying the same request cannot help. `requires_buyer_review` is part of the UCP vocabulary but never emitted by this shop."
          }
        }
      },
      "MessageWarning": {
        "type": "object",
        "description": "A warning: the request was processed, something was adjusted or refused. Never has a `severity`.",
        "additionalProperties": false,
        "required": [
          "type",
          "code",
          "content"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "warning"
          },
          "code": {
            "type": "string",
            "description": "Codes this shop emits: `quantity_adjusted` (a quantity was lowered: to the sellable stock, or to 999 when several lines of one item add up to more — a single line above 999 is lowered to 999 without a message), `discount_code_combination_disallowed`, `discount_code_expired`, `discount_code_user_ineligible`, `discount_code_invalid` (path `$.discounts.codes[i]`), `handed_off` (the buyer already continued on the shop; nothing was changed), `price_filter_ignored` (path `$.filters.price` — the request field: no returned resource carries the filter)."
          },
          "content": {
            "type": "string",
            "description": "A sentence in English for logs and developers. Not localised; do not parse it."
          },
          "path": {
            "type": "string",
            "description": "JSONPath into the RETURNED resource (not the request), e.g. `$.line_items[1].quantity`. Line items are returned in the shop cart’s order, which need not be your order: match lines by `id` or `item.id`, never by position. Absent when the message is about the whole request or about a line that is not in the answer.",
            "pattern": "^\\$"
          }
        }
      },
      "MessageInfo": {
        "type": "object",
        "description": "An informational message. Never has a `severity` or a `path`.",
        "additionalProperties": false,
        "required": [
          "type",
          "code",
          "content"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "info"
          },
          "code": {
            "type": "string",
            "description": "This shop emits `not_found` (catalog lookup: an identifier that matched nothing)."
          },
          "content": {
            "type": "string",
            "description": "For `not_found`: the identifier as you sent it (after trimming)."
          }
        }
      },
      "Message": {
        "description": "A business message. Discriminated by `type`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/MessageError"
          },
          {
            "$ref": "#/components/schemas/MessageWarning"
          },
          {
            "$ref": "#/components/schemas/MessageInfo"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "error": "#/components/schemas/MessageError",
            "warning": "#/components/schemas/MessageWarning",
            "info": "#/components/schemas/MessageInfo"
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "A protocol error: the request could not be processed. It carries no `ucp` object and is always `Cache-Control: no-store`.",
        "additionalProperties": false,
        "required": [
          "code",
          "content"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "invalid_profile_url",
              "profile_unreachable",
              "profile_malformed",
              "version_unsupported",
              "idempotency_conflict",
              "request_too_large",
              "invalid_request",
              "not_found",
              "rate_limited",
              "service_unavailable",
              "internal_error"
            ],
            "description": "The protocol error code (status in brackets): `invalid_profile_url` (400), `invalid_request` (400; 403 from the cross-origin write gate; 415), `request_too_large` (400 for more than 20 lookup ids; 413 for a body over the API’s limits once decompressed: JSON 2 MiB, form-encoded 100 KiB or more than 1 000 fields — a body over 1 MiB as sent is refused by the shop’s web server first, with an HTML 413), `not_found` (404), `idempotency_conflict` (409), `profile_malformed` and `version_unsupported` (422), `profile_unreachable` (424), `rate_limited` (429), `internal_error` (500), `service_unavailable` (503)."
          },
          "content": {
            "type": "string",
            "description": "A sentence in English. For `invalid_request` raised by a body check it names the field, e.g. `line_items[0].quantity must be a positive integer`; errors raised before the body is read (malformed JSON, an unsupported charset) say only `The request is not valid`."
          },
          "continue_url": {
            "type": "string",
            "description": "The shop’s home page (`https://{primary domain}/`). Present only on the discovery errors: `invalid_profile_url`, `profile_unreachable`, `profile_malformed`, `version_unsupported` and the discovery-budget `service_unavailable`.",
            "format": "uri"
          }
        }
      },
      "CurrencyCode": {
        "type": "string",
        "description": "ISO 4217 currency code.",
        "pattern": "^[A-Z]{3}$"
      },
      "Money": {
        "type": "object",
        "description": "An amount with its currency.",
        "additionalProperties": false,
        "required": [
          "amount",
          "currency"
        ],
        "properties": {
          "amount": {
            "type": "integer",
            "description": "ISO 4217 minor units (EUR: cents; JPY: whole yen; HUF: fillér, so 1 990 Ft = 199000). VAT-inclusive whenever the shop knows the gross price, with the shop’s markup rules, conversion and rounding applied — the price its own product page shows."
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          }
        }
      },
      "PriceRange": {
        "type": "object",
        "description": "The lowest and highest of a set of prices.",
        "additionalProperties": false,
        "required": [
          "min",
          "max"
        ],
        "properties": {
          "min": {
            "$ref": "#/components/schemas/Money"
          },
          "max": {
            "$ref": "#/components/schemas/Money"
          }
        }
      },
      "ProductDescription": {
        "type": "object",
        "description": "The product’s description.",
        "additionalProperties": false,
        "required": [
          "plain"
        ],
        "properties": {
          "plain": {
            "type": "string",
            "description": "Plain text: the short description, else the description, with tags removed and common entities decoded; the product title when both are empty. At most 5 000 characters.",
            "maxLength": 5000
          },
          "html": {
            "type": "string",
            "description": "The stored (translated) description HTML, trimmed, at most 50 000 characters (cut, possibly mid-tag). Not sanitised by UCP — sanitise before rendering. Absent when the product has no description.",
            "maxLength": 50000
          }
        }
      },
      "VariantDescription": {
        "type": "object",
        "description": "The variant’s description.",
        "additionalProperties": false,
        "required": [
          "plain"
        ],
        "properties": {
          "plain": {
            "type": "string",
            "description": "The same text as the variant’s `title`."
          }
        }
      },
      "Media": {
        "type": "object",
        "description": "A product image, in the shop’s gallery order (main image first).",
        "additionalProperties": false,
        "required": [
          "type",
          "url"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "image",
            "description": "Always `image`."
          },
          "url": {
            "type": "string",
            "description": "Absolute URL. The shop’s own copies are served from `https://{primary domain}/api/public/…`; vendor images keep the vendor’s URL as stored (some vendor hosts refuse unknown clients).",
            "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://"
          },
          "alt_text": {
            "type": "string",
            "description": "The image’s (translated) alternative text, when set."
          }
        }
      },
      "Barcode": {
        "type": "object",
        "description": "The variant’s GTIN.",
        "additionalProperties": false,
        "required": [
          "type",
          "value"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "EAN",
              "UPC"
            ],
            "description": "`UPC` when the stored GTIN has exactly 12 characters, `EAN` otherwise (GTIN-8, -13 and -14 all read as `EAN`)."
          },
          "value": {
            "type": "string",
            "description": "The GTIN as stored, trimmed."
          }
        }
      },
      "Availability": {
        "type": "object",
        "description": "Stock state, as the shop’s own stock badge reads it.",
        "additionalProperties": false,
        "required": [
          "available",
          "status"
        ],
        "properties": {
          "available": {
            "type": "boolean",
            "description": "Whether the variant can be bought now: `true` for `in_stock` and `preorder`, `false` for `out_of_stock` and `discontinued`."
          },
          "status": {
            "type": "string",
            "enum": [
              "in_stock",
              "preorder",
              "out_of_stock",
              "discontinued"
            ],
            "description": "`discontinued`: the product is not orderable. `preorder`: a warehouse marks it pre-order (no stock limit). `in_stock`: on-hand minus reserved stock is above 0. `out_of_stock`: otherwise. Stock counts are not published."
          }
        }
      },
      "SelectedOption": {
        "type": "object",
        "description": "One option value of a variant.",
        "additionalProperties": false,
        "required": [
          "name",
          "label"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Option name, e.g. `Veľkosť`."
          },
          "label": {
            "type": "string",
            "description": "Option value, e.g. `M`."
          }
        }
      },
      "VariantInput": {
        "type": "object",
        "description": "Which requested identifier this variant answers.",
        "additionalProperties": false,
        "required": [
          "id",
          "match"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The identifier from your `ids`, as you sent it (after trimming; upper-case UUIDs stay upper-case)."
          },
          "match": {
            "type": "string",
            "enum": [
              "exact",
              "featured"
            ],
            "description": "`exact`: the identifier is this variant’s id or SKU. `featured`: it named the product (id or handle) and this is its featured variant."
          }
        }
      },
      "Variant": {
        "type": "object",
        "description": "A purchasable variant. Only active variants with a price in the shop’s region are listed.",
        "additionalProperties": false,
        "required": [
          "id",
          "title",
          "description",
          "url",
          "price",
          "availability"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The variant id — the value to put in `line_items[].item.id`.",
            "format": "uuid"
          },
          "sku": {
            "type": "string",
            "description": "The variant’s SKU, as the shop stores it. Not guaranteed unique — variants of different products may share one. Absent when empty."
          },
          "barcodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Barcode"
            },
            "description": "Present only when a GTIN is stored.",
            "minItems": 1,
            "maxItems": 1
          },
          "title": {
            "type": "string",
            "description": "The option labels joined by ` / ` (e.g. `Modrá / M`); the product title for a variant without options."
          },
          "description": {
            "$ref": "#/components/schemas/VariantDescription"
          },
          "url": {
            "type": "string",
            "description": "The product’s page on the shop (no variant parameter).",
            "format": "uri"
          },
          "price": {
            "$ref": "#/components/schemas/Money"
          },
          "list_price": {
            "$ref": "#/components/schemas/Money",
            "description": "The compare-at price, only when it is higher than `price`. Shown as the shop shows it; the shop may store it without VAT, so treat it as indicative."
          },
          "availability": {
            "$ref": "#/components/schemas/Availability"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SelectedOption"
            },
            "description": "The variant’s option values (after the shop’s value mapping). Absent when it has none.",
            "minItems": 1
          },
          "inputs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VariantInput"
            },
            "description": "Catalog lookup only: the identifiers this variant answers.",
            "minItems": 1
          }
        }
      },
      "ProductOption": {
        "type": "object",
        "description": "An option of the product and the values its listed variants have.",
        "additionalProperties": false,
        "required": [
          "name",
          "values"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Option name."
          },
          "values": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One value.",
              "additionalProperties": false,
              "required": [
                "label"
              ],
              "properties": {
                "label": {
                  "type": "string",
                  "description": "Option value."
                }
              }
            },
            "description": "Values in first-seen order over the listed variants.",
            "minItems": 1
          }
        }
      },
      "ProductDetailOption": {
        "type": "object",
        "description": "An option with availability signals relative to `selected`.",
        "additionalProperties": false,
        "required": [
          "name",
          "values"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Option name."
          },
          "values": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One value with its availability next to the current selection.",
              "additionalProperties": false,
              "required": [
                "label",
                "exists",
                "available"
              ],
              "properties": {
                "label": {
                  "type": "string",
                  "description": "Option value."
                },
                "exists": {
                  "type": "boolean",
                  "description": "Some variant has this value together with every other option value of the selected variant."
                },
                "available": {
                  "type": "boolean",
                  "description": "Such a variant is `availability.available`."
                }
              }
            },
            "description": "Values in first-seen order.",
            "minItems": 1
          }
        }
      },
      "Product": {
        "type": "object",
        "description": "A product as search and lookup return it. Fields not published: categories, ratings, stock counts, delivery times, sales-unit data.\n\nIn **lookup** answers `variants` holds only the variants your identifiers matched (each with `inputs`), while `price_range`, `list_price_range` and `options` still describe all of the product’s priced variants (within the price filter, when one is set).",
        "additionalProperties": false,
        "required": [
          "id",
          "title",
          "description",
          "url",
          "price_range",
          "variants"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The product id. Stable for the product’s life.",
            "format": "uuid"
          },
          "handle": {
            "type": "string",
            "description": "The product’s URL slug in the answer’s language. Absent when the product has none."
          },
          "title": {
            "type": "string",
            "description": "The product title in the answer’s language (prefix and suffix included)."
          },
          "description": {
            "$ref": "#/components/schemas/ProductDescription"
          },
          "url": {
            "type": "string",
            "description": "The product page on the shop’s primary domain: `https://{primary domain}/products/{handle, else id}`.",
            "format": "uri"
          },
          "price_range": {
            "$ref": "#/components/schemas/PriceRange",
            "description": "Over the listed variants’ `price`."
          },
          "list_price_range": {
            "$ref": "#/components/schemas/PriceRange",
            "description": "Over the variants’ `list_price`; absent when none has one."
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Media"
            },
            "description": "Up to 20 images; absent when there is none.",
            "minItems": 1,
            "maxItems": 20
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductOption"
            },
            "description": "The product’s options; absent when variants have no options.",
            "minItems": 1
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            },
            "description": "Priced variants (within the price filter, if any). The first available variant comes first; the others follow in the order the shop’s catalog returns them, which is not guaranteed to be stable.",
            "minItems": 1
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "The brand name."
            },
            "description": "Only the brand name, when the product has a brand.",
            "minItems": 1,
            "maxItems": 1
          }
        }
      },
      "ProductDetail": {
        "type": "object",
        "description": "A product as `getProduct` returns it: every priced variant, the selected one first, and per-value availability.",
        "additionalProperties": false,
        "required": [
          "id",
          "title",
          "description",
          "url",
          "price_range",
          "variants"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The product id. Stable for the product’s life.",
            "format": "uuid"
          },
          "handle": {
            "type": "string",
            "description": "The product’s URL slug in the answer’s language. Absent when the product has none."
          },
          "title": {
            "type": "string",
            "description": "The product title in the answer’s language (prefix and suffix included)."
          },
          "description": {
            "$ref": "#/components/schemas/ProductDescription"
          },
          "url": {
            "type": "string",
            "description": "The product page on the shop’s primary domain: `https://{primary domain}/products/{handle, else id}`.",
            "format": "uri"
          },
          "price_range": {
            "$ref": "#/components/schemas/PriceRange",
            "description": "Over the listed variants’ `price`."
          },
          "list_price_range": {
            "$ref": "#/components/schemas/PriceRange",
            "description": "Over the variants’ `list_price`; absent when none has one."
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Media"
            },
            "description": "Up to 20 images; absent when there is none.",
            "minItems": 1,
            "maxItems": 20
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductDetailOption"
            },
            "description": "The product’s options with availability relative to `selected`; absent when variants have no options.",
            "minItems": 1
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            },
            "description": "All priced variants. The selected (anchor) variant comes first.",
            "minItems": 1
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "The brand name."
            },
            "description": "Only the brand name, when the product has a brand.",
            "minItems": 1,
            "maxItems": 1
          },
          "selected": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SelectedOption"
            },
            "description": "The option values of the selected variant (`variants[0]`) — not necessarily what you sent. Absent when it has no options.",
            "minItems": 1
          }
        }
      },
      "RequestContext": {
        "type": [
          "object",
          "null"
        ],
        "description": "Buyer context. Every field is optional; strings longer than the stated length are cut (counted in code points). Unknown fields (`intent`, `eligibility`, `payment` …) are ignored.",
        "properties": {
          "address_country": {
            "type": [
              "string",
              "null"
            ],
            "description": "The buyer’s country: ISO 3166-1 alpha-2 (`SK`; `UK` reads as `GB`), alpha-3 (`SVK`) or an English, Slovak, Czech, Hungarian, German … country name. Not recognised → silently dropped. Stored and echoed only: it does not change prices or shipping (shipping uses the destination’s country).",
            "maxLength": 60
          },
          "address_region": {
            "type": [
              "string",
              "null"
            ],
            "description": "Region. Stored and echoed only.",
            "maxLength": 100
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Postal code. Stored and echoed only.",
            "maxLength": 20
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "Preferred language, a BCP 47-like tag matching `^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$` and at most 35 characters (otherwise silently dropped). Tried before `Accept-Language`; see that header for the matching rules. It decides the currency.",
            "maxLength": 100
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 4217 code (`^[A-Za-z]{3}$`, upper-cased; otherwise silently dropped). **Does not change the currency of prices**, which follows the language. In catalog requests it only says which currency `filters.price` is in (without it, the bounds are in the answer’s currency).",
            "maxLength": 10
          }
        }
      },
      "PriceFilter": {
        "type": "object",
        "description": "Keeps a variant when `min ≤ price.amount ≤ max` (the final VAT-inclusive amount); a product stays while any variant does. The bounds are in `context.currency`, else (no `context.currency`, or one the API cannot read) in the currency of the answer, which the language decides. In the answer’s currency → used as sent; another currency → converted at the shop’s exchange rate (min rounded down, max up), or — with no rate — ignored with a `price_filter_ignored` warning.\n\nDecimals and negative numbers → `400 invalid_request`. `min > max` matches nothing.",
        "properties": {
          "min": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Lowest price, inclusive, in minor units of `context.currency` (else of the answer’s currency)."
          },
          "max": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Highest price, inclusive, in minor units of `context.currency` (else of the answer’s currency)."
          }
        }
      },
      "SearchFilters": {
        "type": "object",
        "description": "Filters. Other filters (brand, availability …) are ignored without a message.",
        "properties": {
          "price": {
            "$ref": "#/components/schemas/PriceFilter"
          },
          "categories": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "pattern": "^\\s*$"
            },
            "description": "Not supported. A list holding any non-blank value → `400 invalid_request` \"filters.categories is not supported by this shop; search by query (and filters.price) instead\". An empty list reads as absent."
          }
        }
      },
      "CatalogSearchRequest": {
        "type": "object",
        "description": "A catalog search. The whole body is optional: no body (or `{}`) lists every product. Unknown fields (`signals`, …) are ignored.",
        "properties": {
          "query": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free text; longer text is cut to 200 characters. Matches, case-insensitively (but not ignoring diacritics) as a substring, the product title in the answer’s language or the product code / external ids — not descriptions, brands, variant SKUs or GTINs (use lookup for SKUs). Absent: every listed product.",
            "maxLength": 200
          },
          "filters": {
            "$ref": "#/components/schemas/SearchFilters"
          },
          "pagination": {
            "type": "object",
            "description": "Paging.",
            "properties": {
              "limit": {
                "type": "integer",
                "description": "Page size, default 10. A value above 20 is lowered to 20; 0, decimals and strings → 400.",
                "minimum": 1,
                "default": 10
              },
              "cursor": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "`pagination.cursor` from the previous answer. Opaque, at most 40 characters. It carries only the page number: resend the same `query`, `filters`, `limit` and `context` with it.",
                "maxLength": 40
              }
            }
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          }
        }
      },
      "CatalogLookupRequest": {
        "type": "object",
        "description": "A batch lookup by identifier. Unknown fields are ignored.",
        "required": [
          "ids"
        ],
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Up to 20 identifiers, each a variant id (any case), a variant SKU (exact, case-sensitive; several products may share one), a product id or a product handle (in any language). Non-string and blank entries are dropped, exact duplicates removed. Empty or missing → 400 `invalid_request`; more than 20 → 400 `request_too_large`.",
            "minItems": 1,
            "maxItems": 20
          },
          "filters": {
            "$ref": "#/components/schemas/SearchFilters"
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          }
        }
      },
      "GetProductRequest": {
        "type": "object",
        "description": "A product detail request. `preferences` and other unknown fields are ignored.",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "A product id, a product handle or a variant id (SKUs are not accepted here). Required; longer text is cut to 255 characters.",
            "minLength": 1,
            "maxLength": 255
          },
          "selected": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 20,
            "items": {
              "type": "object",
              "description": "An option value to select.",
              "required": [
                "name",
                "label"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Option name.",
                  "maxLength": 100
                },
                "label": {
                  "type": "string",
                  "description": "Option value.",
                  "maxLength": 255
                }
              }
            },
            "description": "Option values to select (names and labels compared case-insensitively). The variant matching all of them becomes the anchor; when none does, selections are dropped from the end until one matches. `selected` wins over a variant id in `id`. Entries without both fields are skipped; at most the first 20 are read. Relaxation is not reported."
          },
          "filters": {
            "$ref": "#/components/schemas/SearchFilters",
            "description": "Only `filters.categories` is checked (and refused when non-blank); `filters.price` is ignored here."
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          }
        }
      },
      "CatalogPagination": {
        "type": "object",
        "description": "Search paging.",
        "additionalProperties": false,
        "required": [
          "has_next_page"
        ],
        "properties": {
          "has_next_page": {
            "type": "boolean",
            "description": "Whether another page may follow. Pages can be short or even empty while this is `true` (products without a priced variant, or outside the price filter, are dropped after the page is read): keep following `cursor` until it is `false`."
          },
          "cursor": {
            "type": "string",
            "description": "Send it as `pagination.cursor` for the next page. Present only when `has_next_page` is `true`.",
            "maxLength": 40
          },
          "total_count": {
            "type": "integer",
            "description": "Number of listed products matching `query`, counted before the per-variant price checks. Left out whenever a price filter is in effect.",
            "minimum": 0
          }
        }
      },
      "CatalogSearchResponse": {
        "type": "object",
        "description": "A page of search results.",
        "additionalProperties": false,
        "required": [
          "ucp",
          "products",
          "pagination"
        ],
        "properties": {
          "ucp": {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          "products": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Product"
            },
            "description": "Newest product first (there is no relevance ranking)."
          },
          "pagination": {
            "$ref": "#/components/schemas/CatalogPagination"
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            },
            "description": "Present only when non-empty. Search emits only `price_filter_ignored`.",
            "minItems": 1
          }
        }
      },
      "CatalogLookupResponse": {
        "type": "object",
        "description": "Lookup results. No pagination.",
        "additionalProperties": false,
        "required": [
          "ucp",
          "products"
        ],
        "properties": {
          "ucp": {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          "products": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Product"
            },
            "description": "One entry per product, in the order its first identifier appears in `ids`; each holds only the matched variants."
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            },
            "description": "Present only when non-empty: `price_filter_ignored` first, then one `info` `not_found` per identifier that matched nothing, in `ids` order.",
            "minItems": 1
          }
        }
      },
      "GetProductResponse": {
        "type": "object",
        "description": "One product in detail.",
        "additionalProperties": false,
        "required": [
          "ucp",
          "product"
        ],
        "properties": {
          "ucp": {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          "product": {
            "$ref": "#/components/schemas/ProductDetail"
          }
        }
      },
      "LineItemRequest": {
        "type": "object",
        "description": "One requested line.",
        "required": [
          "item"
        ],
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "A line id from an earlier answer. Accepted and ignored (whatever its type): lines are matched by `item.id`.",
            "maxLength": 100
          },
          "item": {
            "type": "object",
            "description": "What to buy.",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "A variant id from the catalog (longer text is cut to 100 characters). A product id is accepted too and means the product’s active variant created first — not necessarily the featured, available or priced variant the catalog shows (the answer then names that variant). Ids are checked against the company’s published products, not against this storefront’s catalog: its exclusion filters do not apply, so send only variant ids this shop’s catalog returned. Anything else — a SKU, an unknown id — is not a 400: the line is left out with an `item_unavailable` message.",
                "minLength": 1,
                "maxLength": 100
              }
            }
          },
          "quantity": {
            "type": "integer",
            "description": "How many, default 1. 0, negatives, decimals and strings → 400. A value above 999 is lowered to 999 without a message; lines of the same variant are summed, and a sum above 999 is lowered with a `quantity_adjusted` warning. A quantity above the sellable stock is lowered with `quantity_adjusted`; a sold-out variant is left out with `out_of_stock`. Pre-order variants are never limited.",
            "minimum": 1,
            "default": 1
          }
        }
      },
      "BuyerRequest": {
        "type": [
          "object",
          "null"
        ],
        "description": "**Replaces the whole stored buyer**: a field you leave out is erased (send the e-mail again when you add a name). `null` clears the buyer; leaving `buyer` out keeps it. A non-string value → 400; a longer string is cut to the stated length (counted in code points). Names and phone are never required.",
        "properties": {
          "first_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "At most 100 characters.",
            "maxLength": 100
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "At most 100 characters.",
            "maxLength": 100
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "At most 254 characters. Lower-cased when it looks like an address (`^[^@\\s\"]{1,64}@[^@\\s\"]{1,255}$`); any other string is stored as sent, and a checkout then reports `missing` at `$.buyer.email`.",
            "maxLength": 254
          },
          "phone_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "At most 40 characters.",
            "maxLength": 40
          }
        }
      },
      "PostalAddressRequest": {
        "type": "object",
        "description": "A shipping address. Strings longer than stated are cut; a non-string → 400.",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your id for this address, used only to pick it with `selected_destination_id`. Not echoed: the answer always says `destination`.",
            "maxLength": 100
          },
          "street_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Street and number. Required for a ready checkout.",
            "maxLength": 255
          },
          "extended_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Apartment, floor …",
            "maxLength": 255
          },
          "address_locality": {
            "type": [
              "string",
              "null"
            ],
            "description": "City. Required for a ready checkout.",
            "maxLength": 100
          },
          "address_region": {
            "type": [
              "string",
              "null"
            ],
            "description": "Region.",
            "maxLength": 100
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Postal code. Required for a ready checkout.",
            "maxLength": 20
          },
          "address_country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Country: alpha-2, alpha-3 or a country name. Required for a ready checkout. On the chosen destination an unrecognised value → 400 `invalid_request` \"…address_country is not a recognised country; send an ISO 3166-1 alpha-2 code such as \\\"SK\\\"\".",
            "maxLength": 60
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient first name.",
            "maxLength": 100
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient last name.",
            "maxLength": 100
          },
          "phone_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient phone.",
            "maxLength": 40
          }
        }
      },
      "FulfillmentRequest": {
        "type": [
          "object",
          "null"
        ],
        "description": "Shipping (only read when `dev.ucp.shopping.fulfillment` is negotiated; ignored on carts — a cart stores it but never uses it, and a conversion takes `fulfillment` from the conversion request). `null` or a body without `fulfillment` keeps what the session holds.",
        "properties": {
          "methods": {
            "type": [
              "array",
              "null"
            ],
            "description": "Only the first method (of the first 10) whose `type` is `shipping` or absent is read; `pickup` and other types are ignored.",
            "items": {
              "type": "object",
              "description": "A fulfillment method.",
              "properties": {
                "type": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "`shipping` (or absent). Other types are ignored."
                },
                "destinations": {
                  "type": [
                    "array",
                    "null"
                  ],
                  "items": {
                    "$ref": "#/components/schemas/PostalAddressRequest"
                  },
                  "description": "Addresses (the first 10 are read). The one named by `selected_destination_id`, else the first, becomes the session’s shipping address and replaces the stored one. A stored address cannot be removed, only replaced."
                },
                "selected_destination_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "The `id` of the address to use. A non-string, or one that names no address, is ignored: the first address is used.",
                  "maxLength": 100
                },
                "groups": {
                  "type": "array",
                  "description": "Only `groups[0]` is read (a non-array is ignored).",
                  "items": {
                    "type": "object",
                    "description": "The single group.",
                    "properties": {
                      "selected_option_id": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "An option `id` from `fulfillment.methods[0].groups[0].options` of an earlier answer. `null` clears the choice; absent — or an empty string or a non-string — keeps it. A choice that is not (or no longer) offered stays stored, reads as `null` and adds `invalid_option`.",
                        "maxLength": 100
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "DiscountsRequest": {
        "type": [
          "object",
          "null"
        ],
        "description": "Discount codes (only read when `dev.ucp.shopping.discount` is negotiated). Without the extension a code is never applied: one applied earlier is taken off the session’s cart for that answer (the stored codes are kept, and a later request that negotiates the extension applies them again).",
        "properties": {
          "codes": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 10,
            "items": {
              "type": "string",
              "maxLength": 50
            },
            "description": "Discount codes, **replacing** the stored list; `[]` clears them, `null` or absent keeps them. At most 10 (counted before duplicates are removed; more → 400), each cut to 50 characters; blanks and non-strings dropped; duplicates removed case-insensitively. The shop applies **one** code: the first it accepts. Every later code gets `discount_code_combination_disallowed`; a refused code gets `discount_code_expired`, `discount_code_user_ineligible` (below the code’s minimum order total, which is compared with the subtotal without VAT, before the discount) or `discount_code_invalid`. On a session that has never held a line every code reads as `discount_code_invalid`; the stored codes are tried again on every create and update (not on cancel)."
          }
        }
      },
      "CartCreateRequest": {
        "type": "object",
        "description": "A new cart. Unknown fields are ignored. Body problems are reported before anything is stored.",
        "required": [
          "line_items"
        ],
        "properties": {
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItemRequest"
            },
            "description": "The lines. Required; `[]` creates an empty cart. If lines are sent and none can be added the answer is a 200 business error and no cart exists.",
            "maxItems": 100
          },
          "buyer": {
            "$ref": "#/components/schemas/BuyerRequest"
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          },
          "discounts": {
            "$ref": "#/components/schemas/DiscountsRequest"
          },
          "fulfillment": {
            "$ref": "#/components/schemas/FulfillmentRequest",
            "description": "Accepted and stored, never used for a cart (validated like a checkout’s when the fulfillment extension is negotiated, so a malformed one is still a 400)."
          }
        }
      },
      "CartUpdateRequest": {
        "type": "object",
        "description": "A cart update. Fields you leave out keep their stored value (except that `line_items` is required). Every write extends `expires_at` to 7 days from now.",
        "required": [
          "line_items"
        ],
        "properties": {
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItemRequest"
            },
            "description": "**Required, full replacement**: lines not listed are removed. Missing → 400 `line_items must be an array`.",
            "maxItems": 100
          },
          "buyer": {
            "$ref": "#/components/schemas/BuyerRequest"
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          },
          "discounts": {
            "$ref": "#/components/schemas/DiscountsRequest"
          },
          "fulfillment": {
            "$ref": "#/components/schemas/FulfillmentRequest",
            "description": "Accepted and stored, never used for a cart (validated like a checkout’s when the fulfillment extension is negotiated, so a malformed one is still a 400)."
          }
        }
      },
      "CheckoutCreateRequest": {
        "type": "object",
        "description": "A new checkout session, directly from lines or from a cart. Send `line_items`, or `cart_id` to convert a cart (read only when `dev.ucp.shopping.cart` is negotiated). Without a usable `cart_id`, `line_items` is required: a missing one is `400 invalid_request` \"line_items must be an array\". Unknown fields are ignored.",
        "properties": {
          "cart_id": {
            "type": "string",
            "description": "Convert this cart (only when `dev.ucp.shopping.cart` is negotiated; otherwise it is ignored and `line_items` is required). The checkout takes the cart’s lines, buyer, context and language — `line_items`, `buyer` and `context` in this request are ignored (`buyer` and `context` are still checked: a malformed one is a 400) — its `fulfillment` from this request, and its discount codes from this request when `discounts.codes` is sent (else the cart’s). The cart itself is not changed. One open checkout per cart: when the cart already has one, that checkout is answered with HTTP 200 and this request’s fields are not applied. A cart whose lines the buyer already took to the shop → 200 `handed_off`. An unknown id → 200 `not_found` (\"Checkout session not found\")."
          },
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItemRequest"
            },
            "description": "The lines (direct create). Required unless `cart_id` converts a cart; `[]` creates an empty, `incomplete` checkout.",
            "maxItems": 100
          },
          "buyer": {
            "$ref": "#/components/schemas/BuyerRequest"
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          },
          "fulfillment": {
            "$ref": "#/components/schemas/FulfillmentRequest"
          },
          "discounts": {
            "$ref": "#/components/schemas/DiscountsRequest"
          }
        }
      },
      "CheckoutUpdateRequest": {
        "type": "object",
        "description": "A checkout update. Fields you leave out keep their stored value; `{}` is valid: it re-derives the status, quotes the shipping options again, applies the stored discount codes again (with the discount extension) and extends `expires_at`; it does not check the lines again. Every update of an open checkout extends `expires_at` to 24 h from now.",
        "properties": {
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItemRequest"
            },
            "description": "Optional. When sent, **full replacement**; absent keeps the lines.",
            "maxItems": 100
          },
          "buyer": {
            "$ref": "#/components/schemas/BuyerRequest"
          },
          "context": {
            "$ref": "#/components/schemas/RequestContext"
          },
          "fulfillment": {
            "$ref": "#/components/schemas/FulfillmentRequest"
          },
          "discounts": {
            "$ref": "#/components/schemas/DiscountsRequest"
          }
        }
      },
      "CheckoutCompleteRequest": {
        "type": "object",
        "description": "Ignored. Any `payment`, `payment_data` or AP2 field is ignored and never stored: no payment is processed through UCP. The body still counts for the Idempotency-Key’s request identity.",
        "additionalProperties": true
      },
      "LineItemTotal": {
        "type": "object",
        "description": "A line amount. `subtotal` and `total` are equal: discounts are not allocated to lines.",
        "additionalProperties": false,
        "required": [
          "type",
          "amount"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "subtotal",
              "total"
            ]
          },
          "amount": {
            "type": "integer",
            "description": "The line’s total (unit price × quantity). Integer in ISO 4217 minor units of the session’s `currency` (EUR: cents), VAT included.",
            "minimum": 0
          }
        }
      },
      "LineItem": {
        "type": "object",
        "description": "A line of the shop cart that prices the session.",
        "additionalProperties": false,
        "required": [
          "id",
          "item",
          "quantity",
          "totals"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The line id. Stable while the line exists; new after a language change, and different in a checkout made from a cart.",
            "format": "uuid"
          },
          "item": {
            "type": "object",
            "description": "The variant on this line.",
            "additionalProperties": false,
            "required": [
              "id",
              "title",
              "price"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "The variant id — also when the request named a product id.",
                "format": "uuid"
              },
              "title": {
                "type": "string",
                "description": "The product title in the session’s language (the variant id when there is none) — never the variant’s title: two lines of one product read the same. Identify the variant by `item.id` (keep the `title` and `options` the catalog showed for it, or look it up)."
              },
              "price": {
                "type": "integer",
                "description": "Unit price. Integer in ISO 4217 minor units of the session’s `currency` (EUR: cents), VAT included.",
                "minimum": 0
              },
              "image_url": {
                "type": "string",
                "description": "The product’s main image, absolute. Absent when there is none.",
                "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://"
              }
            }
          },
          "quantity": {
            "type": "integer",
            "description": "Quantity after adjustments (stock, the 999 cap), in the unit the shop sells — one package for goods sold in packages. UCP publishes no package content.",
            "minimum": 1,
            "maximum": 999
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItemTotal"
            },
            "description": "`[subtotal, total]`.",
            "minItems": 2,
            "maxItems": 2
          }
        }
      },
      "Total": {
        "type": "object",
        "description": "One total. Order: `subtotal`, `discount`?, `fulfillment`?, `total`; every entry except `total` sums to `total`. Payment-method surcharges are chosen on the shop and never quoted.",
        "additionalProperties": false,
        "required": [
          "type",
          "amount"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "subtotal",
              "discount",
              "fulfillment",
              "total"
            ],
            "description": "`subtotal`: sum of the line totals. `discount` (negative; only when a code is applied with an amount above 0): what the shop deducts — a percentage code is a percentage of the subtotal WITHOUT VAT, deducted from this VAT-inclusive subtotal, exactly as the shop’s checkout charges it. `fulfillment` (checkouts, only once a valid shipping option is selected; may be 0): the shipping fee. `total`: `subtotal + discount + fulfillment`."
          },
          "amount": {
            "type": "integer",
            "description": "The amount. Integer in ISO 4217 minor units of the session’s `currency` (EUR: cents), VAT included."
          },
          "display_text": {
            "type": "string",
            "description": "On `discount`: the applied code, upper-cased."
          }
        }
      },
      "Buyer": {
        "type": "object",
        "description": "The stored buyer; empty fields are left out. Absent when nothing is stored.",
        "additionalProperties": false,
        "properties": {
          "first_name": {
            "type": "string",
            "description": "As stored."
          },
          "last_name": {
            "type": "string",
            "description": "As stored."
          },
          "email": {
            "type": "string",
            "description": "As stored (lower-cased when it looks like an address)."
          },
          "phone_number": {
            "type": "string",
            "description": "As stored."
          }
        },
        "minProperties": 1
      },
      "Context": {
        "type": "object",
        "description": "The stored context, echoed as you sent it (after cleaning); empty fields are left out. Absent when nothing is stored.",
        "additionalProperties": false,
        "properties": {
          "address_country": {
            "type": "string",
            "description": "Alpha-2 country code.",
            "pattern": "^[A-Z]{2}$"
          },
          "address_region": {
            "type": "string",
            "description": "As sent."
          },
          "postal_code": {
            "type": "string",
            "description": "As sent."
          },
          "language": {
            "type": "string",
            "description": "The language you sent — not necessarily the one the session uses (that is not published; the currency and titles show it)."
          },
          "currency": {
            "type": "string",
            "description": "As sent (upper-cased). Not the currency of the prices.",
            "pattern": "^[A-Z]{3}$"
          }
        },
        "minProperties": 1
      },
      "AppliedDiscount": {
        "type": "object",
        "description": "The code the shop applied.",
        "additionalProperties": false,
        "required": [
          "code",
          "title",
          "amount",
          "method"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "The applied code, upper-cased."
          },
          "title": {
            "type": "string",
            "description": "The same as `code`."
          },
          "amount": {
            "type": "integer",
            "description": "The deduction, positive. Integer in ISO 4217 minor units of the session’s `currency` (EUR: cents), VAT included.",
            "minimum": 1
          },
          "method": {
            "type": "string",
            "const": "across",
            "description": "Always `across` (spread over the whole cart)."
          }
        }
      },
      "Discounts": {
        "type": "object",
        "description": "Present only when `dev.ucp.shopping.discount` is negotiated. The `discount` total is present whether or not it is.",
        "additionalProperties": false,
        "required": [
          "codes",
          "applied"
        ],
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "A code."
            },
            "description": "The codes you asked for, as stored (your spelling, duplicates removed).",
            "maxItems": 10
          },
          "applied": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppliedDiscount"
            },
            "description": "At most one entry: the session’s cart holds one code.",
            "maxItems": 1
          }
        }
      },
      "ShippingDestination": {
        "type": "object",
        "description": "The stored shipping address; empty fields are left out.",
        "additionalProperties": false,
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "const": "destination",
            "description": "Always `destination` (your own id is not echoed)."
          },
          "street_address": {
            "type": "string",
            "description": "As sent."
          },
          "extended_address": {
            "type": "string",
            "description": "As sent."
          },
          "address_locality": {
            "type": "string",
            "description": "As sent."
          },
          "address_region": {
            "type": "string",
            "description": "As sent."
          },
          "postal_code": {
            "type": "string",
            "description": "As sent."
          },
          "address_country": {
            "type": "string",
            "description": "Alpha-2 country code.",
            "pattern": "^[A-Z]{2}$"
          },
          "first_name": {
            "type": "string",
            "description": "As sent."
          },
          "last_name": {
            "type": "string",
            "description": "As sent."
          },
          "phone_number": {
            "type": "string",
            "description": "As sent."
          }
        }
      },
      "FulfillmentOption": {
        "type": "object",
        "description": "A shipping option: one of the shop’s active shipping methods, filtered by the destination country (no destination → no country filter) and by the methods’ product rules. No carrier code, delivery date or pickup flag is published.",
        "additionalProperties": false,
        "required": [
          "id",
          "title",
          "totals"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The shipping method’s id — the value for `selected_option_id`.",
            "format": "uuid"
          },
          "title": {
            "type": "string",
            "description": "The method’s name in the session’s language."
          },
          "description": {
            "type": "string",
            "description": "The method’s description in the session’s language, else its own description (which can be in another language of the shop), else the English `Delivery in {min}–{max} business days` (or `Delivery in {n} business days`) from its delivery estimate; absent when none exists. At most 300 characters.",
            "maxLength": 300
          },
          "totals": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "The fee.",
              "additionalProperties": false,
              "required": [
                "type",
                "amount"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "const": "total"
                },
                "amount": {
                  "type": "integer",
                  "description": "The shipping fee for this checkout — the same rule the shop’s checkout charges (0 once the cart’s subtotal without VAT reaches the method’s free-shipping threshold). Integer in ISO 4217 minor units of the session’s `currency` (EUR: cents), VAT included.",
                  "minimum": 0
                }
              }
            },
            "description": "One entry.",
            "minItems": 1,
            "maxItems": 1
          }
        }
      },
      "FulfillmentGroup": {
        "type": "object",
        "description": "The single shipping group.",
        "additionalProperties": false,
        "required": [
          "id",
          "line_item_ids",
          "options",
          "selected_option_id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "const": "default"
          },
          "line_item_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "A line id.",
              "format": "uuid"
            },
            "description": "Every line of the checkout."
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FulfillmentOption"
            },
            "description": "In the shop’s order. Empty while the checkout has no line or the shop does not ship to the destination."
          },
          "selected_option_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The selected option, only when it is among `options`; otherwise `null`."
          }
        }
      },
      "FulfillmentMethod": {
        "type": "object",
        "description": "The single shipping method covering every line.",
        "additionalProperties": false,
        "required": [
          "id",
          "type",
          "line_item_ids",
          "groups"
        ],
        "properties": {
          "id": {
            "type": "string",
            "const": "shipping"
          },
          "type": {
            "type": "string",
            "const": "shipping"
          },
          "line_item_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "A line id.",
              "format": "uuid"
            },
            "description": "Every line of the checkout."
          },
          "destinations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ShippingDestination"
            },
            "description": "Present once an address is stored.",
            "minItems": 1,
            "maxItems": 1
          },
          "selected_destination_id": {
            "type": "string",
            "const": "destination",
            "description": "Present once an address is stored."
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FulfillmentGroup"
            },
            "description": "Exactly one group.",
            "minItems": 1,
            "maxItems": 1
          }
        }
      },
      "Fulfillment": {
        "type": "object",
        "description": "Present only when `dev.ucp.shopping.fulfillment` is negotiated. One `shipping` method with one group; there is no `pickup` method — a pickup point (Packeta) is chosen by the buyer on the shop.",
        "additionalProperties": false,
        "required": [
          "methods"
        ],
        "properties": {
          "methods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FulfillmentMethod"
            },
            "description": "Exactly one method.",
            "minItems": 1,
            "maxItems": 1
          }
        }
      },
      "Link": {
        "type": "object",
        "description": "A legal link from the shop’s checkout consents.",
        "additionalProperties": false,
        "required": [
          "type",
          "url"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "terms_of_service",
              "privacy_policy"
            ],
            "description": "`privacy_policy` when the consent’s label, link text or URL looks like a privacy one (privacy, GDPR, osobn…, súkrom…, adatvédel…, Datenschutz, ochrana …); otherwise `terms_of_service`."
          },
          "url": {
            "type": "string",
            "description": "Absolute; a relative shop link is made absolute on the primary domain.",
            "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://"
          },
          "title": {
            "type": "string",
            "description": "The consent’s link text, else its label, at most 200 characters; absent when empty.",
            "maxLength": 200
          }
        }
      },
      "Order": {
        "type": "object",
        "description": "The order the buyer placed on the shop.",
        "additionalProperties": false,
        "required": [
          "id",
          "permalink_url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The order id (the parent order when the shop split it by VAT).",
            "format": "uuid"
          },
          "label": {
            "type": "string",
            "description": "The shop’s order number. Absent when the order has none.",
            "maxLength": 50
          },
          "permalink_url": {
            "type": "string",
            "description": "The shop’s order confirmation page, `https://{primary domain}/order-confirmation?orderNumber=…&orderId=…` (`orderNumber` only when there is one). Renders without a sign-in; shows the number, not the order’s status.",
            "format": "uri"
          }
        }
      },
      "ContinueUrl": {
        "type": "string",
        "description": "The buyer handoff link, `https://{primary domain}/ucp/continue/{64 hex}`. Give it to the BUYER to open in their browser; never call it yourself. It never changes during the session’s life and works while the session is open and unexpired — an `incomplete` checkout included: the first line that reaches a buyer’s cart freezes the session in the status it has, so give the link only at `requires_escalation`. Once a cart was converted, its own link hands over the checkout made from it. Not single-use: every distinct browser (or signed-in customer) that opens it gets the lines once.",
        "format": "uri",
        "pattern": "^https://[^/]+/ucp/continue/[0-9a-f]{64}$"
      },
      "ExpiresAt": {
        "type": "string",
        "description": "When the session expires (UTC, ISO 8601 with milliseconds). A write extends it (cart: now + 7 days, checkout: now + 24 h); reads, `complete` and `cancel` do not. After a handoff nothing extends it.",
        "format": "date-time"
      },
      "Cart": {
        "type": "object",
        "description": "A cart. It has **no `status`**: a cancel answers the cart as it was (with `continue_url`), and only a later read shows `not_found`.",
        "additionalProperties": false,
        "required": [
          "ucp",
          "id",
          "line_items",
          "currency",
          "totals",
          "continue_url",
          "expires_at"
        ],
        "properties": {
          "ucp": {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          "id": {
            "type": "string",
            "description": "The cart id.",
            "format": "uuid"
          },
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItem"
            },
            "description": "In the shop cart’s order, which need not be the order you sent."
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Total"
            },
            "description": "`subtotal`, `discount`? and `total` (never `fulfillment` on a cart).",
            "minItems": 2,
            "maxItems": 3
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            },
            "description": "Present only when non-empty. Line and discount messages appear only in the answer to the write that caused them (a cart the buyer took to the shop repeats its last answer, messages included).",
            "minItems": 1
          },
          "buyer": {
            "$ref": "#/components/schemas/Buyer"
          },
          "context": {
            "$ref": "#/components/schemas/Context"
          },
          "discounts": {
            "$ref": "#/components/schemas/Discounts"
          },
          "continue_url": {
            "$ref": "#/components/schemas/ContinueUrl"
          },
          "expires_at": {
            "$ref": "#/components/schemas/ExpiresAt"
          }
        }
      },
      "CheckoutStatus": {
        "type": "string",
        "enum": [
          "incomplete",
          "requires_escalation",
          "completed",
          "canceled"
        ],
        "description": "* `incomplete` — at least one `recoverable` error is listed (no line, no valid e-mail, no or incomplete address, no shipping to it, no or an unoffered option, a line error in this answer).\n* `requires_escalation` — nothing the platform can provide is missing; `payment_required` is listed and the buyer must continue on the shop through `continue_url`.\n* `completed` — the buyer placed an order on the shop from the cart the handoff filled; see `order`. It means *placed*, not *paid*. Set shortly after the order (once the shop has started the payment and handed the order to its ERP) and best effort: a failure is only logged, so an order can exist for a checkout that never reads `completed`.\n* `canceled` — canceled by `POST …/cancel`, or expired (an open checkout read or written after `expires_at` turns `canceled`).\n\n`ready_for_complete` and `complete_in_progress` are never used: the API never completes a checkout."
      },
      "Checkout": {
        "type": "object",
        "description": "A checkout session.\n\nOnce `completed` or `canceled` — and while the buyer’s handoff is done but the order not yet placed — the body is the **last answer the platform received**, with the current `status` (and `order`): it is not re-priced, and it does not show what the buyer changed on the shop. Only the lines and the applied discount code travel to the shop; the buyer enters address, shipping and payment there again.",
        "additionalProperties": false,
        "required": [
          "ucp",
          "id",
          "status",
          "currency",
          "line_items",
          "totals",
          "messages",
          "links",
          "expires_at"
        ],
        "properties": {
          "ucp": {
            "$ref": "#/components/schemas/CheckoutResponseMetadata"
          },
          "id": {
            "type": "string",
            "description": "The checkout session id.",
            "format": "uuid"
          },
          "status": {
            "$ref": "#/components/schemas/CheckoutStatus"
          },
          "currency": {
            "$ref": "#/components/schemas/CurrencyCode"
          },
          "line_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItem"
            },
            "description": "In the shop cart’s order."
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Total"
            },
            "description": "`subtotal`, `discount`?, `fulfillment`?, `total`.",
            "minItems": 2,
            "maxItems": 4
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            },
            "description": "Always present, possibly empty. Order: line messages and discount messages (only in the answer to the write that caused them), then `missing` / `invalid_address` / `address_undeliverable` / `invalid_option`, `pickup_point_required`, and `payment_required` last. Empty on `completed` and `canceled` reads."
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Link"
            },
            "description": "Always present: at most 10, possibly empty.",
            "maxItems": 10
          },
          "buyer": {
            "$ref": "#/components/schemas/Buyer"
          },
          "context": {
            "$ref": "#/components/schemas/Context"
          },
          "fulfillment": {
            "$ref": "#/components/schemas/Fulfillment"
          },
          "discounts": {
            "$ref": "#/components/schemas/Discounts"
          },
          "continue_url": {
            "$ref": "#/components/schemas/ContinueUrl",
            "description": "Present while the checkout is `incomplete` or `requires_escalation`; absent once `completed` or `canceled`."
          },
          "expires_at": {
            "$ref": "#/components/schemas/ExpiresAt"
          },
          "order": {
            "$ref": "#/components/schemas/Order",
            "description": "Present once `completed`."
          }
        }
      },
      "BusinessProfile": {
        "type": "object",
        "description": "The business profile. Apart from the capabilities a shop in catalog mode leaves out, the only value that differs between shops is the host in `endpoint` (the primary domain).",
        "additionalProperties": false,
        "required": [
          "ucp"
        ],
        "properties": {
          "ucp": {
            "type": "object",
            "description": "The profile. There is no `supported_versions`, no `signing_keys`, no business name or logo.",
            "additionalProperties": false,
            "required": [
              "version",
              "services",
              "capabilities",
              "payment_handlers"
            ],
            "properties": {
              "version": {
                "$ref": "#/components/schemas/UcpVersion"
              },
              "services": {
                "type": "object",
                "description": "One service.",
                "additionalProperties": false,
                "required": [
                  "dev.ucp.shopping"
                ],
                "properties": {
                  "dev.ucp.shopping": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The REST binding.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "transport",
                        "endpoint",
                        "schema"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/overview`.",
                          "format": "uri"
                        },
                        "transport": {
                          "type": "string",
                          "const": "rest",
                          "description": "REST is the only transport (no MCP, A2A or embedded)."
                        },
                        "endpoint": {
                          "type": "string",
                          "description": "The REST base URL, `https://{primary domain}/ucp/v1`. Call this.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json` (the protocol’s own OpenAPI).",
                          "format": "uri"
                        }
                      }
                    }
                  }
                }
              },
              "capabilities": {
                "type": "object",
                "description": "What this shop declares. A shop in catalog mode (it takes no orders) declares only the two catalog capabilities.",
                "additionalProperties": false,
                "required": [
                  "dev.ucp.shopping.catalog.search",
                  "dev.ucp.shopping.catalog.lookup"
                ],
                "properties": {
                  "dev.ucp.shopping.catalog.search": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The declaration of `dev.ucp.shopping.catalog.search`.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "schema"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/…` for this capability.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/schemas/shopping/….json` for this capability.",
                          "format": "uri"
                        }
                      }
                    }
                  },
                  "dev.ucp.shopping.catalog.lookup": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The declaration of `dev.ucp.shopping.catalog.lookup`.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "schema"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/…` for this capability.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/schemas/shopping/….json` for this capability.",
                          "format": "uri"
                        }
                      }
                    }
                  },
                  "dev.ucp.shopping.cart": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The declaration of `dev.ucp.shopping.cart`.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "schema"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/…` for this capability.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/schemas/shopping/….json` for this capability.",
                          "format": "uri"
                        }
                      }
                    }
                  },
                  "dev.ucp.shopping.checkout": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The declaration of `dev.ucp.shopping.checkout`.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "schema"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/…` for this capability.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/schemas/shopping/….json` for this capability.",
                          "format": "uri"
                        }
                      }
                    }
                  },
                  "dev.ucp.shopping.fulfillment": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The declaration of `dev.ucp.shopping.fulfillment`.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "schema",
                        "extends"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/…` for this capability.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/schemas/shopping/….json` for this capability.",
                          "format": "uri"
                        },
                        "extends": {
                          "type": "string",
                          "const": "dev.ucp.shopping.checkout",
                          "description": "The parent capability."
                        }
                      }
                    }
                  },
                  "dev.ucp.shopping.discount": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 1,
                    "items": {
                      "type": "object",
                      "description": "The declaration of `dev.ucp.shopping.discount`.",
                      "additionalProperties": false,
                      "required": [
                        "version",
                        "spec",
                        "schema",
                        "extends"
                      ],
                      "properties": {
                        "version": {
                          "$ref": "#/components/schemas/UcpVersion"
                        },
                        "spec": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/specification/…` for this capability.",
                          "format": "uri"
                        },
                        "schema": {
                          "type": "string",
                          "description": "`https://ucp.dev/2026-04-08/schemas/shopping/….json` for this capability.",
                          "format": "uri"
                        },
                        "extends": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/CapabilityName"
                          },
                          "description": "The parent capabilities: `[\"dev.ucp.shopping.checkout\",\"dev.ucp.shopping.cart\"]`."
                        }
                      }
                    }
                  }
                }
              },
              "payment_handlers": {
                "type": "object",
                "maxProperties": 0,
                "description": "Always `{}`: the buyer pays on the shop’s own checkout."
              }
            }
          }
        }
      },
      "HandoffClaimRequest": {
        "type": "object",
        "description": "Sent by the handoff page’s own script.",
        "required": [
          "sessionId"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "description": "The browser’s storefront guest-cart id (`localStorage[\"sf-cart\"].state.sessionId`; the page creates one when there is none). 8–128 characters of `A-Z a-z 0-9 _ -`, not starting with `ucp_`. It is not the UCP session id.",
            "pattern": "^(?!ucp_)[A-Za-z0-9_-]{8,128}$"
          }
        }
      },
      "HandoffClaimResponse": {
        "type": "object",
        "description": "Where the buyer’s browser goes next.",
        "additionalProperties": false,
        "required": [
          "redirect"
        ],
        "properties": {
          "redirect": {
            "type": "string",
            "enum": [
              "/checkout",
              "/cart",
              "/"
            ],
            "description": "Same-origin path the page continues to: `/checkout` for a checkout (also when a cart link handed over the cart’s open checkout), `/cart` for a cart (and when nothing could be added because the browser’s cart holds items in another currency), `/` on a shop in catalog mode."
          }
        }
      },
      "UcpBusinessErrorResponse": {
        "type": "object",
        "description": "HTTP 200 with no resource. The cases:\n\n* `capabilities_incompatible` — your profile and this shop share no version of the operation’s root capability (always for carts and checkouts on a shop in catalog mode). Nothing ran; no Idempotency-Key was used.\n* `not_found` — the product, cart (`Cart not found or has expired`) or checkout (`Checkout session not found`) does not exist for this shop, is malformed, or (carts) was canceled or expired. An unknown `cart_id` on `POST /checkout-sessions` also reads `Checkout session not found`.\n* `out_of_stock` / `item_unavailable` — a create in which none of the requested items could be added; no session was created.\n* `handed_off` — converting a cart whose lines the buyer already took to the shop.\n\nInside a write the last three are stored under the Idempotency-Key like a success (`capabilities_incompatible` is answered before the key is read).",
        "additionalProperties": false,
        "required": [
          "ucp",
          "messages",
          "continue_url"
        ],
        "properties": {
          "ucp": {
            "$ref": "#/components/schemas/ErrorResponseMetadata"
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MessageError"
            },
            "minItems": 1,
            "maxItems": 1,
            "description": "Exactly one error message saying why no resource could be returned."
          },
          "continue_url": {
            "type": "string",
            "description": "Where a buyer could go instead: the shop home (`https://{primary domain}/`), or `https://{primary domain}/cart` for `handed_off`. Not a handoff link.",
            "format": "uri"
          }
        }
      }
    },
    "securitySchemes": {
      "storefrontCustomerToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Monokaido storefront access token",
        "description": "`Authorization: Bearer <storefront access token>` (the token matches `[A-Za-z0-9_.-]{16,4096}`) of the shop customer signed in in that browser tab, which the handoff page reads from the storefront’s session storage. A valid token of a customer of this shop’s company sends the lines to that customer’s cart; a missing, invalid or expired token, or one of another shop’s company, makes the request a guest request (never an error). Used only by the browser-only handoff claim."
      }
    },
    "parameters": {
      "UcpAgent": {
        "name": "UCP-Agent",
        "in": "header",
        "required": true,
        "description": "Names your platform profile. Required on every `/ucp/v1/*` operation; never read by the profile and handoff routes.\n\n**Grammar** — a subset of an RFC 8941 *Dictionary*, at most 4096 characters:\n\n* members separated by `,` (spaces or tabs around it allowed; a trailing comma is an error); keys lower-case, matching `[a-z*][a-z0-9_\\-.*]*`;\n* the `profile` member must be an sf-string: `profile=\"https://…\"`, printable ASCII 0x20–0x7E, escapes `\\\"` and `\\\\` only;\n* other members (tokens, numbers, booleans, strings) and parameters (`;key=value`) are parsed and ignored; when `profile` appears twice the last one wins;\n* any parse error makes the whole header unusable.\n\nAccepted: `profile=\"https://platform.example.com/.well-known/ucp\"`, `version=\"2026-04-08\", profile=\"https://platform.example.com/.well-known/ucp\";sig=abc`. Refused: a missing header, `profile=https://…` (a token, not a string), `Profile=\"…\"`, `a=1 b=2, profile=\"…\"`.\n\n**The URL** — at most 1000 characters, no whitespace anywhere, starting `https://`, no user name or password, a non-empty host. Any port, path and query string are accepted (the spec’s `/.well-known/ucp` path is not enforced). Failing any rule → `400 invalid_profile_url`.\n\n**The fetch** — `GET` with `Accept: application/json` and `User-Agent: Monokaido-UCP/1.0 (+https://monokaido.com)`; no redirects followed; only HTTP 200 accepted; at most 256 KiB; 3 s idle, 5 s total; the host must resolve to a public address (private, loopback, link-local and other reserved ranges are refused). Anything else → `424 profile_unreachable`. A body that is not JSON, or whose `ucp.version` is not a `YYYY-MM-DD` string → `422 profile_malformed`; a valid profile of another version → `422 version_unsupported`. Only `ucp.version` and `ucp.capabilities` (name → `[{\"version\"}]`, first 20 entries per name, names like `dev.ucp.shopping.cart`) are read; everything else in it is ignored.\n\n**Caching** — a fetched profile is cached for its `Cache-Control: max-age`, clamped to 60 s – 1 h (5 min without one; `no-store`, `no-cache` and `private` are ignored) and served up to 1 h past that while one background refresh runs. A failed fetch (`424`, or `422 profile_malformed`) is remembered for 60 s. A profile of another `ucp.version` is a valid profile and is cached like one, so after you change its version expect `422 version_unsupported` until that entry is refreshed (its `max-age`, then one more request) — or use a new profile URL. These caches are kept in memory by each API process. Fetching a profile the shop does not know yet is budgeted: 5 new profile URLs per minute per client (IPv4 address, IPv6 /64) and 60 per minute in all → `503 service_unavailable` with `Retry-After`. The full URL string is the cache key, so keep it stable (no per-request query strings).",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 4096
        },
        "example": "profile=\"https://platform.example.com/.well-known/ucp\""
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "**Optional, strongly recommended.** Without it (or with an empty value) the write simply runs: a retried create makes a second session.\n\n* Format: 1–255 printable ASCII characters 0x21–0x7E — no spaces. Anything else (also a header sent twice, which arrives joined with `\", \"`) → `400 invalid_request` \"Idempotency-Key is not valid\". A UUID v4 per logical write is a good choice.\n* Scope: this shop (all its domains) × the exact `UCP-Agent` profile URL string × the key.\n* Request identity: the operation, the path `{id}` as sent (after URL decoding; case included) and the JSON body compared canonically (object key order and whitespace do not matter, array order does). Cancel routes hash `{}` whatever the body.\n* Same key, same request, finished → the stored HTTP status and body are replayed — the same values, including a 200 business error, the original `expires_at` and the `ucp` object negotiated the first time, even when the session has changed since. The replay comes from storage, so its object keys come in JSONB order (and its `ETag` differs).\n* The `UCP-Agent` profile is resolved and negotiated before the key is read: a profile error or a 200 `capabilities_incompatible` answer is never stored.\n* Same key, different request → `409 idempotency_conflict`. Same request still running → `409` with `Retry-After: 2`.\n* If the first request fails with a protocol error (`400`, `503` session busy, `500` …) the key is released: retrying with the same key runs the operation again.\n* A claim whose request died is taken over by the same request after 120 s. Keys are kept for at least 25 hours after their first use (an hourly job deletes older ones); do not rely on a key more than 24 hours after its first use.\n* Not read by catalog operations, `GET` routes, the profile or the handoff routes.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255,
          "pattern": "^[\\x21-\\x7E]{1,255}$"
        },
        "example": "0c2f8a4e-6b1d-4f37-9a85-3e7d1c9b5f02"
      },
      "AcceptLanguage": {
        "name": "Accept-Language",
        "in": "header",
        "required": false,
        "description": "Fallback for the answer’s language after `context.language` in the body. The first 10 comma-separated tags are tried **in header order** (`q=` weights are ignored, `*` is skipped) against the languages the shop offers: an exact tag (case-insensitive), then the primary subtag (`en-US` → `en-GB`); with no match, the shop’s first language. (A storefront without a language list of its own offers every language of the company: then the primary subtag of the first usable tag is used as it is — a language the company has not set up is answered in its default currency, untranslated — and, with no tag at all, the company’s default language.)\n\nThe language decides the currency of every price and the translations. A cart or checkout keeps the language it was created in: a later request changes it only when its body names a `context.language` different from the stored one, and when that switches the shop language every line is re-added in the new currency and gets a new line id. Once a session has a language, this header alone never switches it. On a storefront without a language list, a session created with no usable tag stores none: each later request is then answered in the language its own tags pick, and a different pick adds the lines again (new line ids). Send `context.language` on the create.",
        "schema": {
          "type": "string"
        },
        "example": "sk-SK,sk;q=0.9,en;q=0.8"
      },
      "CartId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The cart’s `id` (a UUID, any letter case). An id that is not a UUID, belongs to another shop, or names a canceled or expired cart is answered with the 200 `not_found` business error, not a 4xx.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
        },
        "example": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83"
      },
      "CheckoutId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The checkout session’s `id` (a UUID, any letter case). An id that is not a UUID or belongs to another shop is answered with the 200 `not_found` business error, not a 4xx. Completed and canceled checkouts stay readable until 30 days after `expires_at`.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
        },
        "example": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97"
      },
      "ContinueToken": {
        "name": "token",
        "in": "path",
        "required": true,
        "description": "The session’s continue token: exactly 64 lower-case hexadecimal characters, the last path segment of `continue_url`. It is a secret of its own, never the session id, and never changes. Anything else is treated as an unknown token.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$"
        },
        "example": "9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b"
      }
    },
    "headers": {
      "CacheControlNoStore": {
        "description": "Every UCP answer (success or error) except the business profile.",
        "schema": {
          "type": "string",
          "const": "no-store"
        }
      },
      "CacheControlProfile": {
        "description": "The business profile may be cached for 5 minutes by anyone.",
        "schema": {
          "type": "string",
          "const": "public, max-age=300"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying: 60 after `429 rate_limited` and the generic `503`; 1 when another request holds the session; 2 when the same Idempotency-Key is still running; 10 when profile discovery is busy; the rest of the current minute (at least 1) when your client used its 5 new profiles this minute.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "RateLimitLimit": {
        "description": "Requests this client IP may make to this operation per 60-second window (600 reads, 300 writes, 60 handoff). Set on every answer that passed the rate limiter.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "The operation’s limit minus this client IP’s current count. The counts live in the API server’s memory; each request is meant to leave the count 60 s after it was made, but the rate limiter (`@nestjs/throttler` 6.5) drops those pending decrements, for every client, whenever any client’s block ends. Read it as an upper bound and keep steady traffic at half a limit or less.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RateLimitReset": {
        "description": "Seconds left in a 60-second window the limiter keeps per client IP and operation. The count is not reset when that window ends, so this is not the moment the budget comes back.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "ETag": {
        "description": "An ETag of the body, generated by the API on every response with a body (writes included). The API’s ETag is strong; the web server sends it weak (`W/\"…\"`) when it compresses the response, which it does for a client that sends `Accept-Encoding: gzip`. A `GET` that sends a matching `If-None-Match` (either form) can be answered `304 Not Modified` even though the answer is `no-store`.",
        "schema": {
          "type": "string"
        }
      },
      "ContentSecurityPolicy": {
        "description": "The handoff page’s policy: only its own inline script (by hash), same-origin `fetch`, inline styles. The shop’s web server may add its own policy as a second header.",
        "schema": {
          "type": "string"
        },
        "example": "default-src 'none'; script-src 'sha256-VYn/7oWaIZE1N3eYOOLF7hjVtQcwMb7njm95xAMru14='; connect-src 'self'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'"
      },
      "ReferrerPolicy": {
        "description": "What a browser receives on the handoff page, from two layers: the API sends `no-referrer`, and the shop’s web server adds its general `strict-origin-when-cross-origin` as a second `Referrer-Policy` field after it. A browser applies the last valid value, so the header alone gives `strict-origin-when-cross-origin`. The page’s `<meta name=\"referrer\" content=\"no-referrer\">`, applied after the header, is what keeps the token out of every `Referer`.",
        "schema": {
          "type": "string"
        },
        "example": "no-referrer, strict-origin-when-cross-origin"
      },
      "XRobotsTag": {
        "description": "The handoff page is never indexed.",
        "schema": {
          "type": "string",
          "const": "noindex, nofollow"
        }
      }
    },
    "responses": {
      "NotModified": {
        "description": "Not Modified — only when the request sent `If-None-Match` equal to the current answer’s `ETag` (strong as the API generates it on every response, or the weak `W/\"…\"` form the web server sends with a compressed answer). No body. Clients that do not send `If-None-Match` never see it.",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          }
        }
      },
      "NoBusinessOnHost": {
        "description": "`not_found`. Either the host serves no UCP — an unknown host, a `*.shop.monokaido.com` subdomain, a domain without verified DNS or an active certificate, UCP switched off, the built-in storefront off, an inactive or expired storefront key, or the e-shop module off; one answer for all, on purpose — or the path or method does not exist under `/ucp/` (an unknown method is 404, not 405). A domain that has no certificate of its own yet never gets this answer: its TLS handshake fails first. A missing cart, checkout or product is NOT this: it is a 200 business error.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorNoBusinessOnHost": {
                "$ref": "#/components/examples/ErrorNoBusinessOnHost"
              },
              "ErrorRouteNotFound": {
                "$ref": "#/components/examples/ErrorRouteNotFound"
              }
            }
          }
        }
      },
      "IdempotencyConflict": {
        "description": "`idempotency_conflict`. The `Idempotency-Key` was used for a different request (409, no `Retry-After`), or the same request is still running (409, `Retry-After: 2`). Writes only.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorIdempotencyConflict": {
                "$ref": "#/components/examples/ErrorIdempotencyConflict"
              },
              "ErrorIdempotencyInProgress": {
                "$ref": "#/components/examples/ErrorIdempotencyInProgress"
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Payload Too Large, from one of two layers:\n\n* **The web server** (`text/html`): a request body over 1 MiB, whatever its content type. Not produced by the API: nginx, the web server in front of the shop, answers it with its own HTML page. No `Cache-Control: no-store`.\n* **The API** (`application/json`, `request_too_large` \"Request body too large\"): a body over the API’s own limits once decompressed — 2 MiB for JSON, 100 KiB or more than 1 000 fields for `application/x-www-form-urlencoded`. A JSON body reaches this through the shop’s domain only when it is sent compressed (`Content-Encoding`), since the web server limits the body as sent to 1 MiB.\n\nBodies of this API are far below either limit: 100 line items take a few kilobytes.",
        "content": {
          "text/html": {
            "schema": {
              "type": "string",
              "description": "nginx error page."
            },
            "examples": {
              "NginxPayloadTooLarge": {
                "$ref": "#/components/examples/NginxPayloadTooLarge"
              }
            }
          },
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorRequestTooLarge": {
                "$ref": "#/components/examples/ErrorRequestTooLarge"
              }
            }
          }
        },
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore",
            "description": "On the API’s JSON answer only."
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "`invalid_request` \"The request is not valid\" with HTTP 415: the body declares a charset its parser does not read (JSON: `charset=` must start with `utf-`; form-encoded: `utf-8` or `iso-8859-1`), or a `Content-Encoding` other than `gzip`, `deflate`, `br` or `identity`. Send `Content-Type: application/json` (UTF-8). A body of another content type is not read at all.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorUnsupportedCharset": {
                "$ref": "#/components/examples/ErrorUnsupportedCharset"
              }
            }
          }
        }
      },
      "ProfileProblem": {
        "description": "Unprocessable Content — your platform profile: `profile_malformed` (not JSON, no `ucp` object, no `YYYY-MM-DD` `ucp.version`; remembered for 60 s) or `version_unsupported` (`ucp.version` is not `2026-04-08`). Both carry `continue_url` (the shop home). Fix the profile. A `profile_malformed` failure is remembered for 60 s for that exact URL; a profile of another version is a valid profile and stays cached for its `max-age` (60 s – 1 h, 5 min without one), so `version_unsupported` persists until that entry is refreshed — or change the profile URL.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorProfileMalformed": {
                "$ref": "#/components/examples/ErrorProfileMalformed"
              },
              "ErrorVersionUnsupported": {
                "$ref": "#/components/examples/ErrorVersionUnsupported"
              }
            }
          }
        }
      },
      "ProfileUnreachable": {
        "description": "Failed Dependency — `profile_unreachable`: your platform profile could not be fetched (network error, timeout, a redirect, a status other than 200, over 256 KiB, a non-public address). Remembered for 60 s for that exact URL.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorProfileUnreachable": {
                "$ref": "#/components/examples/ErrorProfileUnreachable"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too Many Requests, from one of two layers:\n\n* **The API** (`application/json`, `rate_limited`, `Retry-After: 60`): this client IP’s count for the operation passed its limit (see `X-RateLimit-Remaining`) — 600 for reads, 300 for writes, 60 for the handoff routes, each operation counted separately, across every Monokaido shop.\n* **The web server** (`text/html`): above 100 requests/s per client IP, burst 200: one budget for everything that IP sends to any shop host Monokaido serves (UCP calls, pages and images alike) and to the storefront API, not per shop. Not produced by the API: nginx, the web server in front of the shop, answers it with its own HTML page. No `Retry-After`.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorRateLimited": {
                "$ref": "#/components/examples/ErrorRateLimited"
              }
            }
          },
          "text/html": {
            "schema": {
              "type": "string",
              "description": "nginx error page."
            },
            "examples": {
              "NginxTooManyRequests": {
                "$ref": "#/components/examples/NginxTooManyRequests"
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "`internal_error`: an unexpected failure (logged on the server; no detail is sent). A failed write released its Idempotency-Key: retry with the same key.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorInternal": {
                "$ref": "#/components/examples/ErrorInternal"
              }
            }
          }
        }
      },
      "BadGateway": {
        "description": "Bad Gateway — the API is down or restarting. Not produced by the API: nginx, the web server in front of the shop, answers it with its own HTML page.",
        "content": {
          "text/html": {
            "schema": {
              "type": "string",
              "description": "nginx error page."
            },
            "examples": {
              "NginxBadGateway": {
                "$ref": "#/components/examples/NginxBadGateway"
              }
            }
          }
        }
      },
      "GatewayTimeout": {
        "description": "Gateway Timeout — the API did not answer within 60 s. Not produced by the API: nginx, the web server in front of the shop, answers it with its own HTML page. A write may have been applied: retry it with the same Idempotency-Key.",
        "content": {
          "text/html": {
            "schema": {
              "type": "string",
              "description": "nginx error page."
            },
            "examples": {
              "NginxGatewayTimeout": {
                "$ref": "#/components/examples/NginxGatewayTimeout"
              }
            }
          }
        }
      },
      "ShopUnavailable": {
        "description": "`service_unavailable` \"This shop is temporarily unavailable\", `Retry-After: 60`: the shop’s company is deactivated or billing-locked, or the shop lookup failed.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorShopUnavailable": {
                "$ref": "#/components/examples/ErrorShopUnavailable"
              }
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "`service_unavailable`, always with `Retry-After`:\n\n* \"This shop is temporarily unavailable\" (`Retry-After: 60`) — the company is deactivated or billing-locked, or the shop lookup failed;\n* \"Too many new platform profiles from this client, retry shortly\" (`Retry-After`: the rest of the one-minute window) — your IP started 5 fetches of unknown profile URLs this minute;\n* \"Platform profile discovery is busy, retry shortly\" (`Retry-After: 10`).",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorShopUnavailable": {
                "$ref": "#/components/examples/ErrorShopUnavailable"
              },
              "ErrorDiscoveryClientBudget": {
                "$ref": "#/components/examples/ErrorDiscoveryClientBudget"
              },
              "ErrorDiscoveryBusy": {
                "$ref": "#/components/examples/ErrorDiscoveryBusy"
              }
            }
          }
        }
      },
      "ServiceUnavailableSession": {
        "description": "`service_unavailable`, always with `Retry-After`:\n\n* \"Another request on this session is being processed — retry shortly\" (`Retry-After: 1`) — another request on the same cart or checkout was running and this one could not get its turn within 10 s, or 4 were already waiting behind it (this request did not run); or, rarely, another writer changed the session while this request ran (its result was not stored). Either way the Idempotency-Key was released: retry the same request with the same key;\n* \"This shop is temporarily unavailable\" (`Retry-After: 60`);\n* the two profile-discovery answers (see `UCP-Agent`).\n\nKeep at most one request in flight per session.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorSessionBusy": {
                "$ref": "#/components/examples/ErrorSessionBusy"
              },
              "ErrorShopUnavailable": {
                "$ref": "#/components/examples/ErrorShopUnavailable"
              },
              "ErrorDiscoveryClientBudget": {
                "$ref": "#/components/examples/ErrorDiscoveryClientBudget"
              },
              "ErrorDiscoveryBusy": {
                "$ref": "#/components/examples/ErrorDiscoveryBusy"
              }
            }
          }
        }
      },
      "CrossOriginRejected": {
        "description": "Forbidden — `invalid_request` \"The request is not valid\" from the platform’s cross-origin write gate: the POST / PUT carried a Monokaido session cookie (`accessToken`, `refreshToken`, `platformAccessToken`, `platformRefreshToken`) and was not sent by a page the platform trusts: a `Sec-Fetch-Site` other than `same-origin` / `none` without a trusted `Origin`, or — without `Sec-Fetch-Site` — an `Origin` that is neither trusted nor on the requested host (`Origin: null` included). A server-side client that sends no such cookie never gets it.",
        "headers": {
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControlNoStore"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ErrorCrossOriginRejected": {
                "$ref": "#/components/examples/ErrorCrossOriginRejected"
              }
            }
          }
        }
      }
    },
    "examples": {
      "BusinessProfile": {
        "summary": "Profile of a shop that takes orders",
        "description": "GET https://shop.example.com/.well-known/ucp for a shop whose primary domain is shop.example.com, not in catalog mode.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "services": {
              "dev.ucp.shopping": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/overview",
                  "transport": "rest",
                  "endpoint": "https://shop.example.com/ucp/v1",
                  "schema": "https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json"
                }
              ]
            },
            "capabilities": {
              "dev.ucp.shopping.catalog.search": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/catalog/search",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/catalog_search.json"
                }
              ],
              "dev.ucp.shopping.catalog.lookup": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/catalog/lookup",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/catalog_lookup.json"
                }
              ],
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/cart",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/cart.json"
                }
              ],
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/checkout",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/fulfillment",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/fulfillment.json",
                  "extends": "dev.ucp.shopping.checkout"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/discount",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/discount.json",
                  "extends": [
                    "dev.ucp.shopping.checkout",
                    "dev.ucp.shopping.cart"
                  ]
                }
              ]
            },
            "payment_handlers": {}
          }
        }
      },
      "BusinessProfileCatalogMode": {
        "summary": "Profile of a shop in catalog mode",
        "description": "The same shop with catalog mode in effect (storefront v2 with “Katalógový režim” on): only the two catalog capabilities. Every cart and checkout call then answers 200 `capabilities_incompatible`.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "services": {
              "dev.ucp.shopping": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/overview",
                  "transport": "rest",
                  "endpoint": "https://shop.example.com/ucp/v1",
                  "schema": "https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json"
                }
              ]
            },
            "capabilities": {
              "dev.ucp.shopping.catalog.search": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/catalog/search",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/catalog_search.json"
                }
              ],
              "dev.ucp.shopping.catalog.lookup": [
                {
                  "version": "2026-04-08",
                  "spec": "https://ucp.dev/2026-04-08/specification/catalog/lookup",
                  "schema": "https://ucp.dev/2026-04-08/schemas/shopping/catalog_lookup.json"
                }
              ]
            },
            "payment_handlers": {}
          }
        }
      },
      "CatalogSearchRequest": {
        "summary": "Search “marlin”, two per page",
        "description": "First page of a text search in Slovak. `currency` here only denominates a price filter (none is sent); unknown fields would be ignored.",
        "value": {
          "query": "marlin",
          "pagination": {
            "limit": 2
          },
          "context": {
            "language": "sk",
            "address_country": "SK",
            "currency": "EUR"
          }
        }
      },
      "CatalogSearchNextPageRequest": {
        "summary": "The next page",
        "description": "The same search again with the `cursor` the first page returned (`cDoy` = page 2). Query, limit and context must be repeated: the cursor carries only the page number.",
        "value": {
          "query": "marlin",
          "pagination": {
            "limit": 2,
            "cursor": "cDoy"
          },
          "context": {
            "language": "sk",
            "address_country": "SK",
            "currency": "EUR"
          }
        }
      },
      "CatalogSearchPriceFilterRequest": {
        "summary": "A price filter in another currency",
        "description": "At most 25 000.00 CZK, sent as minor units of `context.currency` (CZK). The shop presents prices in EUR and has no CZK rate stored, so the filter is ignored with a warning.",
        "value": {
          "query": "marlin",
          "filters": {
            "price": {
              "max": 2500000
            }
          },
          "pagination": {
            "limit": 2
          },
          "context": {
            "language": "sk",
            "currency": "CZK"
          }
        }
      },
      "CatalogLookupRequest": {
        "summary": "Four identifiers of four kinds",
        "description": "An upper-case variant id, a variant SKU, a handle that does not exist and a product id.",
        "value": {
          "ids": [
            "7C2F9B1E-4A68-4E3D-B2C9-5D1F7A3E8B06",
            "BOTTLE-750-BLK",
            "trek-marlin-9",
            "a2c94e18-5d37-4b6f-8e21-0f9b3c7d6e15"
          ],
          "context": {
            "language": "sk"
          }
        }
      },
      "GetProductRequest": {
        "summary": "Product detail with a selection",
        "description": "Asks for black (Čierna) in size L. No variant is black and L, so the last selection (size) is dropped and the black variant becomes the anchor.",
        "value": {
          "id": "6f1d2b7c-3a84-4e59-b0c2-8d7e1f4a5b62",
          "selected": [
            {
              "name": "Farba",
              "label": "Čierna"
            },
            {
              "name": "Veľkosť",
              "label": "L"
            }
          ],
          "context": {
            "language": "sk"
          }
        }
      },
      "CatalogSearchResponse": {
        "summary": "First page: two products, more to come",
        "description": "The answer to CatalogSearchRequest. The listing had 3 matches (page 1 of 2), so `has_next_page` is true and `total_count` is 3 (no price filter in effect). The first available variant of Trek Marlin 5 is already first; the pre-order variant counts as available; the vendor image keeps its own URL.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.catalog.search": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "products": [
            {
              "id": "6f1d2b7c-3a84-4e59-b0c2-8d7e1f4a5b62",
              "handle": "trek-marlin-5",
              "title": "Trek Marlin 5",
              "description": {
                "plain": "Horský bicykel s hliníkovým rámom Alpha Silver, odpruženou vidlicou a 29\" kolesami.",
                "html": "<p>Horský bicykel pre začínajúcich jazdcov.</p><ul><li>Rám Alpha Silver Aluminium</li><li>Vidlica SR Suntour XCT 30, zdvih 100 mm</li><li>Pohon Shimano 2×8</li></ul>"
              },
              "url": "https://shop.example.com/products/trek-marlin-5",
              "price_range": {
                "min": {
                  "amount": 69900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 71900,
                  "currency": "EUR"
                }
              },
              "list_price_range": {
                "min": {
                  "amount": 74900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 74900,
                  "currency": "EUR"
                }
              },
              "media": [
                {
                  "type": "image",
                  "url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp",
                  "alt_text": "Trek Marlin 5, modrá, bočný pohľad"
                },
                {
                  "type": "image",
                  "url": "https://images.vendor.example/trek/marlin-5-detail.jpg"
                }
              ],
              "options": [
                {
                  "name": "Farba",
                  "values": [
                    {
                      "label": "Modrá"
                    },
                    {
                      "label": "Čierna"
                    }
                  ]
                },
                {
                  "name": "Veľkosť",
                  "values": [
                    {
                      "label": "M"
                    },
                    {
                      "label": "L"
                    }
                  ]
                }
              ],
              "variants": [
                {
                  "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                  "sku": "MARLIN5-M-MOD",
                  "barcodes": [
                    {
                      "type": "EAN",
                      "value": "8594012345674"
                    }
                  ],
                  "title": "Modrá / M",
                  "description": {
                    "plain": "Modrá / M"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 69900,
                    "currency": "EUR"
                  },
                  "list_price": {
                    "amount": 74900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "in_stock"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Modrá"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "M"
                    }
                  ]
                },
                {
                  "id": "7c2f9b1e-4a68-4e3d-b2c9-5d1f7a3e8b06",
                  "sku": "MARLIN5-L-MOD",
                  "title": "Modrá / L",
                  "description": {
                    "plain": "Modrá / L"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 69900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": false,
                    "status": "out_of_stock"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Modrá"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "L"
                    }
                  ]
                },
                {
                  "id": "d93b4a7e-1f26-4c85-a0e7-3b9c6d2f4e18",
                  "sku": "MARLIN5-M-CIE",
                  "title": "Čierna / M",
                  "description": {
                    "plain": "Čierna / M"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 71900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "preorder"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Čierna"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "M"
                    }
                  ]
                }
              ],
              "tags": [
                "Trek"
              ]
            },
            {
              "id": "2f6c8a1d-7e43-4b95-9c2a-4d1e8b6f3a07",
              "handle": "trek-marlin-7",
              "title": "Trek Marlin 7",
              "description": {
                "plain": "Trek Marlin 7"
              },
              "url": "https://shop.example.com/products/trek-marlin-7",
              "price_range": {
                "min": {
                  "amount": 104900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 104900,
                  "currency": "EUR"
                }
              },
              "media": [
                {
                  "type": "image",
                  "url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-7.webp"
                }
              ],
              "options": [
                {
                  "name": "Veľkosť",
                  "values": [
                    {
                      "label": "L"
                    }
                  ]
                }
              ],
              "variants": [
                {
                  "id": "c8e2a5f1-3d79-4a16-b4e3-9f6c2d8a1e54",
                  "sku": "MARLIN7-L",
                  "title": "L",
                  "description": {
                    "plain": "L"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-7",
                  "price": {
                    "amount": 104900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "in_stock"
                  },
                  "options": [
                    {
                      "name": "Veľkosť",
                      "label": "L"
                    }
                  ]
                }
              ],
              "tags": [
                "Trek"
              ]
            }
          ],
          "pagination": {
            "has_next_page": true,
            "cursor": "cDoy",
            "total_count": 3
          }
        }
      },
      "CatalogSearchPriceFilterIgnored": {
        "summary": "Price filter ignored for lack of an exchange rate",
        "description": "The answer to CatalogSearchPriceFilterRequest: no CZK→EUR (nor EUR→CZK) rate is stored, so `filters.price` is dropped with a `price_filter_ignored` warning, every match is returned and `total_count` stays.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.catalog.search": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "products": [
            {
              "id": "6f1d2b7c-3a84-4e59-b0c2-8d7e1f4a5b62",
              "handle": "trek-marlin-5",
              "title": "Trek Marlin 5",
              "description": {
                "plain": "Horský bicykel s hliníkovým rámom Alpha Silver, odpruženou vidlicou a 29\" kolesami.",
                "html": "<p>Horský bicykel pre začínajúcich jazdcov.</p><ul><li>Rám Alpha Silver Aluminium</li><li>Vidlica SR Suntour XCT 30, zdvih 100 mm</li><li>Pohon Shimano 2×8</li></ul>"
              },
              "url": "https://shop.example.com/products/trek-marlin-5",
              "price_range": {
                "min": {
                  "amount": 69900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 71900,
                  "currency": "EUR"
                }
              },
              "list_price_range": {
                "min": {
                  "amount": 74900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 74900,
                  "currency": "EUR"
                }
              },
              "media": [
                {
                  "type": "image",
                  "url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp",
                  "alt_text": "Trek Marlin 5, modrá, bočný pohľad"
                },
                {
                  "type": "image",
                  "url": "https://images.vendor.example/trek/marlin-5-detail.jpg"
                }
              ],
              "options": [
                {
                  "name": "Farba",
                  "values": [
                    {
                      "label": "Modrá"
                    },
                    {
                      "label": "Čierna"
                    }
                  ]
                },
                {
                  "name": "Veľkosť",
                  "values": [
                    {
                      "label": "M"
                    },
                    {
                      "label": "L"
                    }
                  ]
                }
              ],
              "variants": [
                {
                  "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                  "sku": "MARLIN5-M-MOD",
                  "barcodes": [
                    {
                      "type": "EAN",
                      "value": "8594012345674"
                    }
                  ],
                  "title": "Modrá / M",
                  "description": {
                    "plain": "Modrá / M"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 69900,
                    "currency": "EUR"
                  },
                  "list_price": {
                    "amount": 74900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "in_stock"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Modrá"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "M"
                    }
                  ]
                },
                {
                  "id": "7c2f9b1e-4a68-4e3d-b2c9-5d1f7a3e8b06",
                  "sku": "MARLIN5-L-MOD",
                  "title": "Modrá / L",
                  "description": {
                    "plain": "Modrá / L"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 69900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": false,
                    "status": "out_of_stock"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Modrá"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "L"
                    }
                  ]
                },
                {
                  "id": "d93b4a7e-1f26-4c85-a0e7-3b9c6d2f4e18",
                  "sku": "MARLIN5-M-CIE",
                  "title": "Čierna / M",
                  "description": {
                    "plain": "Čierna / M"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 71900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "preorder"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Čierna"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "M"
                    }
                  ]
                }
              ],
              "tags": [
                "Trek"
              ]
            },
            {
              "id": "2f6c8a1d-7e43-4b95-9c2a-4d1e8b6f3a07",
              "handle": "trek-marlin-7",
              "title": "Trek Marlin 7",
              "description": {
                "plain": "Trek Marlin 7"
              },
              "url": "https://shop.example.com/products/trek-marlin-7",
              "price_range": {
                "min": {
                  "amount": 104900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 104900,
                  "currency": "EUR"
                }
              },
              "media": [
                {
                  "type": "image",
                  "url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-7.webp"
                }
              ],
              "options": [
                {
                  "name": "Veľkosť",
                  "values": [
                    {
                      "label": "L"
                    }
                  ]
                }
              ],
              "variants": [
                {
                  "id": "c8e2a5f1-3d79-4a16-b4e3-9f6c2d8a1e54",
                  "sku": "MARLIN7-L",
                  "title": "L",
                  "description": {
                    "plain": "L"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-7",
                  "price": {
                    "amount": 104900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "in_stock"
                  },
                  "options": [
                    {
                      "name": "Veľkosť",
                      "label": "L"
                    }
                  ]
                }
              ],
              "tags": [
                "Trek"
              ]
            }
          ],
          "pagination": {
            "has_next_page": true,
            "cursor": "cDoy",
            "total_count": 3
          },
          "messages": [
            {
              "type": "warning",
              "code": "price_filter_ignored",
              "path": "$.filters.price",
              "content": "filters.price is denominated in CZK, prices are presented in EUR and cannot be converted, so the price filter was not applied"
            }
          ]
        }
      },
      "CatalogLookupResponse": {
        "summary": "Matched variants only, plus one not_found",
        "description": "The answer to CatalogLookupRequest. Products come in the order of their first identifier. Only the requested variants are listed (each with `inputs`): the out-of-stock Marlin variant asked for by id, the bottle by SKU, and the helmet’s featured variant for its product id. Trek Marlin 5’s `price_range`, `list_price_range` and `options` still span all three of its variants. The unknown handle gets an `info` `not_found` message. The helmet’s 12-character GTIN reads as `UPC`.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.catalog.lookup": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "products": [
            {
              "id": "6f1d2b7c-3a84-4e59-b0c2-8d7e1f4a5b62",
              "handle": "trek-marlin-5",
              "title": "Trek Marlin 5",
              "description": {
                "plain": "Horský bicykel s hliníkovým rámom Alpha Silver, odpruženou vidlicou a 29\" kolesami.",
                "html": "<p>Horský bicykel pre začínajúcich jazdcov.</p><ul><li>Rám Alpha Silver Aluminium</li><li>Vidlica SR Suntour XCT 30, zdvih 100 mm</li><li>Pohon Shimano 2×8</li></ul>"
              },
              "url": "https://shop.example.com/products/trek-marlin-5",
              "price_range": {
                "min": {
                  "amount": 69900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 71900,
                  "currency": "EUR"
                }
              },
              "list_price_range": {
                "min": {
                  "amount": 74900,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 74900,
                  "currency": "EUR"
                }
              },
              "media": [
                {
                  "type": "image",
                  "url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp",
                  "alt_text": "Trek Marlin 5, modrá, bočný pohľad"
                },
                {
                  "type": "image",
                  "url": "https://images.vendor.example/trek/marlin-5-detail.jpg"
                }
              ],
              "options": [
                {
                  "name": "Farba",
                  "values": [
                    {
                      "label": "Modrá"
                    },
                    {
                      "label": "Čierna"
                    }
                  ]
                },
                {
                  "name": "Veľkosť",
                  "values": [
                    {
                      "label": "M"
                    },
                    {
                      "label": "L"
                    }
                  ]
                }
              ],
              "variants": [
                {
                  "id": "7c2f9b1e-4a68-4e3d-b2c9-5d1f7a3e8b06",
                  "sku": "MARLIN5-L-MOD",
                  "title": "Modrá / L",
                  "description": {
                    "plain": "Modrá / L"
                  },
                  "url": "https://shop.example.com/products/trek-marlin-5",
                  "price": {
                    "amount": 69900,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": false,
                    "status": "out_of_stock"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Modrá"
                    },
                    {
                      "name": "Veľkosť",
                      "label": "L"
                    }
                  ],
                  "inputs": [
                    {
                      "id": "7C2F9B1E-4A68-4E3D-B2C9-5D1F7A3E8B06",
                      "match": "exact"
                    }
                  ]
                }
              ],
              "tags": [
                "Trek"
              ]
            },
            {
              "id": "0b7e3f5a-9c12-4d8e-a6f4-2e1c5b9d7a83",
              "handle": "flasa-na-vodu-750-ml",
              "title": "Fľaša na vodu 750 ml",
              "description": {
                "plain": "Fľaša bez BPA s uzáverom proti vytečeniu & úchytom.",
                "html": "<p>Fľaša bez BPA s <b>uzáverom proti vytečeniu</b> &amp; úchytom.</p>"
              },
              "url": "https://shop.example.com/products/flasa-na-vodu-750-ml",
              "price_range": {
                "min": {
                  "amount": 990,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 990,
                  "currency": "EUR"
                }
              },
              "options": [
                {
                  "name": "Farba",
                  "values": [
                    {
                      "label": "Čierna"
                    }
                  ]
                }
              ],
              "variants": [
                {
                  "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                  "sku": "BOTTLE-750-BLK",
                  "title": "Čierna",
                  "description": {
                    "plain": "Čierna"
                  },
                  "url": "https://shop.example.com/products/flasa-na-vodu-750-ml",
                  "price": {
                    "amount": 990,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "in_stock"
                  },
                  "options": [
                    {
                      "name": "Farba",
                      "label": "Čierna"
                    }
                  ],
                  "inputs": [
                    {
                      "id": "BOTTLE-750-BLK",
                      "match": "exact"
                    }
                  ]
                }
              ]
            },
            {
              "id": "a2c94e18-5d37-4b6f-8e21-0f9b3c7d6e15",
              "handle": "cyklisticka-prilba-lumen",
              "title": "Cyklistická prilba Lumen",
              "description": {
                "plain": "Ľahká prilba s integrovaným zadným svetlom."
              },
              "url": "https://shop.example.com/products/cyklisticka-prilba-lumen",
              "price_range": {
                "min": {
                  "amount": 5990,
                  "currency": "EUR"
                },
                "max": {
                  "amount": 5990,
                  "currency": "EUR"
                }
              },
              "variants": [
                {
                  "id": "4a6e2d9c-8b15-4f37-9c48-1e7a5b3d2f90",
                  "sku": "LUMEN-HELM-M",
                  "barcodes": [
                    {
                      "type": "UPC",
                      "value": "859401234567"
                    }
                  ],
                  "title": "Cyklistická prilba Lumen",
                  "description": {
                    "plain": "Cyklistická prilba Lumen"
                  },
                  "url": "https://shop.example.com/products/cyklisticka-prilba-lumen",
                  "price": {
                    "amount": 5990,
                    "currency": "EUR"
                  },
                  "availability": {
                    "available": true,
                    "status": "in_stock"
                  },
                  "inputs": [
                    {
                      "id": "a2c94e18-5d37-4b6f-8e21-0f9b3c7d6e15",
                      "match": "featured"
                    }
                  ]
                }
              ],
              "tags": [
                "Lumen"
              ]
            }
          ],
          "messages": [
            {
              "type": "info",
              "code": "not_found",
              "content": "trek-marlin-9"
            }
          ]
        }
      },
      "GetProductResponse": {
        "summary": "Detail with the black variant selected",
        "description": "The answer to GetProductRequest. The black M variant (pre-order) is the anchor, moved to `variants[0]`; `selected` is its own options (not what was sent). Every option value carries `exists` / `available` next to the other selected values: size L does not exist in black.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.catalog.lookup": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "product": {
            "id": "6f1d2b7c-3a84-4e59-b0c2-8d7e1f4a5b62",
            "handle": "trek-marlin-5",
            "title": "Trek Marlin 5",
            "description": {
              "plain": "Horský bicykel s hliníkovým rámom Alpha Silver, odpruženou vidlicou a 29\" kolesami.",
              "html": "<p>Horský bicykel pre začínajúcich jazdcov.</p><ul><li>Rám Alpha Silver Aluminium</li><li>Vidlica SR Suntour XCT 30, zdvih 100 mm</li><li>Pohon Shimano 2×8</li></ul>"
            },
            "url": "https://shop.example.com/products/trek-marlin-5",
            "price_range": {
              "min": {
                "amount": 69900,
                "currency": "EUR"
              },
              "max": {
                "amount": 71900,
                "currency": "EUR"
              }
            },
            "list_price_range": {
              "min": {
                "amount": 74900,
                "currency": "EUR"
              },
              "max": {
                "amount": 74900,
                "currency": "EUR"
              }
            },
            "media": [
              {
                "type": "image",
                "url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp",
                "alt_text": "Trek Marlin 5, modrá, bočný pohľad"
              },
              {
                "type": "image",
                "url": "https://images.vendor.example/trek/marlin-5-detail.jpg"
              }
            ],
            "options": [
              {
                "name": "Farba",
                "values": [
                  {
                    "label": "Modrá",
                    "exists": true,
                    "available": true
                  },
                  {
                    "label": "Čierna",
                    "exists": true,
                    "available": true
                  }
                ]
              },
              {
                "name": "Veľkosť",
                "values": [
                  {
                    "label": "M",
                    "exists": true,
                    "available": true
                  },
                  {
                    "label": "L",
                    "exists": false,
                    "available": false
                  }
                ]
              }
            ],
            "variants": [
              {
                "id": "d93b4a7e-1f26-4c85-a0e7-3b9c6d2f4e18",
                "sku": "MARLIN5-M-CIE",
                "title": "Čierna / M",
                "description": {
                  "plain": "Čierna / M"
                },
                "url": "https://shop.example.com/products/trek-marlin-5",
                "price": {
                  "amount": 71900,
                  "currency": "EUR"
                },
                "availability": {
                  "available": true,
                  "status": "preorder"
                },
                "options": [
                  {
                    "name": "Farba",
                    "label": "Čierna"
                  },
                  {
                    "name": "Veľkosť",
                    "label": "M"
                  }
                ]
              },
              {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "sku": "MARLIN5-M-MOD",
                "barcodes": [
                  {
                    "type": "EAN",
                    "value": "8594012345674"
                  }
                ],
                "title": "Modrá / M",
                "description": {
                  "plain": "Modrá / M"
                },
                "url": "https://shop.example.com/products/trek-marlin-5",
                "price": {
                  "amount": 69900,
                  "currency": "EUR"
                },
                "list_price": {
                  "amount": 74900,
                  "currency": "EUR"
                },
                "availability": {
                  "available": true,
                  "status": "in_stock"
                },
                "options": [
                  {
                    "name": "Farba",
                    "label": "Modrá"
                  },
                  {
                    "name": "Veľkosť",
                    "label": "M"
                  }
                ]
              },
              {
                "id": "7c2f9b1e-4a68-4e3d-b2c9-5d1f7a3e8b06",
                "sku": "MARLIN5-L-MOD",
                "title": "Modrá / L",
                "description": {
                  "plain": "Modrá / L"
                },
                "url": "https://shop.example.com/products/trek-marlin-5",
                "price": {
                  "amount": 69900,
                  "currency": "EUR"
                },
                "availability": {
                  "available": false,
                  "status": "out_of_stock"
                },
                "options": [
                  {
                    "name": "Farba",
                    "label": "Modrá"
                  },
                  {
                    "name": "Veľkosť",
                    "label": "L"
                  }
                ]
              }
            ],
            "tags": [
              "Trek"
            ],
            "selected": [
              {
                "name": "Farba",
                "label": "Čierna"
              },
              {
                "name": "Veľkosť",
                "label": "M"
              }
            ]
          }
        }
      },
      "ProductNotFound": {
        "summary": "Unknown or hidden product (HTTP 200)",
        "description": "POST /ucp/v1/catalog/product with an id the shop does not show. A business error with HTTP 200, not a 404.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "status": "error",
            "capabilities": {
              "dev.ucp.shopping.catalog.lookup": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "messages": [
            {
              "type": "error",
              "code": "not_found",
              "content": "Product not found",
              "severity": "unrecoverable"
            }
          ],
          "continue_url": "https://shop.example.com/"
        }
      },
      "CartCreateRequest": {
        "summary": "A bike and a helmet",
        "description": "Step 1 of the flow. The helmet line has no `quantity` (1). The e-mail is lower-cased when stored.",
        "value": {
          "line_items": [
            {
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47"
              },
              "quantity": 1
            },
            {
              "item": {
                "id": "4a6e2d9c-8b15-4f37-9c48-1e7a5b3d2f90"
              }
            }
          ],
          "buyer": {
            "email": "Jana.Novakova@Example.com"
          },
          "context": {
            "address_country": "SK",
            "language": "sk"
          }
        }
      },
      "CartCreateSoldOutRequest": {
        "summary": "Only a sold-out variant",
        "description": "The blue L variant is out of stock: no line can be added, so no cart is created.",
        "value": {
          "line_items": [
            {
              "item": {
                "id": "7c2f9b1e-4a68-4e3d-b2c9-5d1f7a3e8b06"
              },
              "quantity": 1
            }
          ]
        }
      },
      "CartUpdateRequest": {
        "summary": "Swap the helmet for three bottles and add two codes",
        "description": "Step 2. `line_items` is a full replacement: the helmet is removed. The line `id` is accepted and ignored (lines match by variant). Only 2 bottles are in stock. `buyer` and `context` are left out, so they are kept.",
        "value": {
          "line_items": [
            {
              "id": "e2b7d4a9-3c61-4f85-9a2e-7d1c5b8f3a46",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47"
              },
              "quantity": 1
            },
            {
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25"
              },
              "quantity": 3
            }
          ],
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ]
          }
        }
      },
      "CartCreated": {
        "summary": "Cart created (201)",
        "description": "The answer to CartCreateRequest: the bike (699.00 €) and the helmet (59.90 €). No `messages` key (none). `discounts` is present because the discount extension is negotiated. The helmet has no image, so no `image_url`. `expires_at` = now + 7 days.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "id": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83",
          "line_items": [
            {
              "id": "e2b7d4a9-3c61-4f85-9a2e-7d1c5b8f3a46",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "5c9e1a7f-2d48-4b36-a8f1-6e3d9c2b7a15",
              "item": {
                "id": "4a6e2d9c-8b15-4f37-9c48-1e7a5b3d2f90",
                "title": "Cyklistická prilba Lumen",
                "price": 5990
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 5990
                },
                {
                  "type": "total",
                  "amount": 5990
                }
              ]
            }
          ],
          "currency": "EUR",
          "totals": [
            {
              "type": "subtotal",
              "amount": 75890
            },
            {
              "type": "total",
              "amount": 75890
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "context": {
            "address_country": "SK",
            "language": "sk"
          },
          "discounts": {
            "codes": [],
            "applied": []
          },
          "continue_url": "https://shop.example.com/ucp/continue/e1f0907c4abcf12564330feef5762f8471cc386a3563ce53cf8342ce6be08b62",
          "expires_at": "2026-11-02T09:14:05.118Z"
        }
      },
      "CartUpdated": {
        "summary": "Cart updated: quantity lowered, one code applied",
        "description": "The answer to CartUpdateRequest. The bottle line was lowered to the 2 in stock (`quantity_adjusted` at its index in the answer); JESEN10 (10 % of the net subtotal 584.39 € = 58.44 €) is applied, LETO5 cannot be combined. Subtotal 718.80 € − 58.44 € = 660.36 €. The kept buyer and context are echoed; `expires_at` moved to now + 7 days.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "id": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83",
          "line_items": [
            {
              "id": "e2b7d4a9-3c61-4f85-9a2e-7d1c5b8f3a46",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "8f4a2c6e-1b93-4d57-b6e8-3a9c7d1f5e24",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "currency": "EUR",
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "total",
              "amount": 66036
            }
          ],
          "messages": [
            {
              "type": "warning",
              "code": "quantity_adjusted",
              "content": "Only 2 available — quantity lowered from 3",
              "path": "$.line_items[1].quantity"
            },
            {
              "type": "warning",
              "code": "discount_code_combination_disallowed",
              "path": "$.discounts.codes[1]",
              "content": "Code 'LETO5' cannot be combined with 'JESEN10'"
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/e1f0907c4abcf12564330feef5762f8471cc386a3563ce53cf8342ce6be08b62",
          "expires_at": "2026-11-02T09:16:47.402Z"
        }
      },
      "CartRetrieved": {
        "summary": "Cart read",
        "description": "GET of the cart after step 2. A read stores nothing and adds no line or discount messages (they belong to the write that caused them); `expires_at` is the stored one. The lines keep their unit prices unless the shop uses live prices.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "id": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83",
          "line_items": [
            {
              "id": "e2b7d4a9-3c61-4f85-9a2e-7d1c5b8f3a46",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "8f4a2c6e-1b93-4d57-b6e8-3a9c7d1f5e24",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "currency": "EUR",
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "total",
              "amount": 66036
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/e1f0907c4abcf12564330feef5762f8471cc386a3563ce53cf8342ce6be08b62",
          "expires_at": "2026-11-02T09:16:47.402Z"
        }
      },
      "CartCanceled": {
        "summary": "Cart canceled",
        "description": "POST …/carts/{id}/cancel after step 2: the cart as it was, with `continue_url` and the stored `expires_at` — a cart has no `status`. Afterwards every operation on it answers CartNotFound, and its `continue_url` shows the “gone” page (410).",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "id": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83",
          "line_items": [
            {
              "id": "e2b7d4a9-3c61-4f85-9a2e-7d1c5b8f3a46",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "8f4a2c6e-1b93-4d57-b6e8-3a9c7d1f5e24",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "currency": "EUR",
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "total",
              "amount": 66036
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/e1f0907c4abcf12564330feef5762f8471cc386a3563ce53cf8342ce6be08b62",
          "expires_at": "2026-11-02T09:16:47.402Z"
        }
      },
      "CartUpdateHandedOff": {
        "summary": "Write after the buyer took the cart to the shop",
        "description": "A PUT on the cart after the buyer opened its `continue_url` following step 2 (before any checkout was made from it): the last stored answer (the step-2 body, its messages kept) with a `handed_off` warning appended. Nothing was changed or stored, whatever the request said. Served from storage, so its keys come in JSONB order.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "id": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83",
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "total",
              "amount": 66036
            }
          ],
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "currency": "EUR",
          "messages": [
            {
              "code": "quantity_adjusted",
              "path": "$.line_items[1].quantity",
              "type": "warning",
              "content": "Only 2 available — quantity lowered from 3"
            },
            {
              "code": "discount_code_combination_disallowed",
              "path": "$.discounts.codes[1]",
              "type": "warning",
              "content": "Code 'LETO5' cannot be combined with 'JESEN10'"
            },
            {
              "type": "warning",
              "code": "handed_off",
              "content": "The buyer continued on the shop: the items are in the shop’s cart now and this session is no longer changed"
            }
          ],
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "expires_at": "2026-11-02T09:16:47.402Z",
          "line_items": [
            {
              "id": "e2b7d4a9-3c61-4f85-9a2e-7d1c5b8f3a46",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "price": 69900,
                "title": "Trek Marlin 5",
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ],
              "quantity": 1
            },
            {
              "id": "8f4a2c6e-1b93-4d57-b6e8-3a9c7d1f5e24",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "price": 990,
                "title": "Fľaša na vodu 750 ml"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ],
              "quantity": 2
            }
          ],
          "continue_url": "https://shop.example.com/ucp/continue/e1f0907c4abcf12564330feef5762f8471cc386a3563ce53cf8342ce6be08b62"
        }
      },
      "CartNotFound": {
        "summary": "Unknown, canceled or expired cart (HTTP 200)",
        "description": "Any cart operation on an id that is not a UUID, belongs to another shop, or names a canceled or expired cart. HTTP 200.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "status": "error",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "messages": [
            {
              "type": "error",
              "code": "not_found",
              "content": "Cart not found or has expired",
              "severity": "unrecoverable"
            }
          ],
          "continue_url": "https://shop.example.com/"
        }
      },
      "CartAllUnavailable": {
        "summary": "None of the items could be added (HTTP 200)",
        "description": "The answer to CartCreateSoldOutRequest: every requested line was sold out, so the new cart was discarded and no id is returned. With mixed reasons the code is `item_unavailable` (\"None of the requested items can be bought in this shop\").",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "status": "error",
            "capabilities": {
              "dev.ucp.shopping.cart": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "messages": [
            {
              "type": "error",
              "code": "out_of_stock",
              "content": "All requested items are currently out of stock",
              "severity": "unrecoverable"
            }
          ],
          "continue_url": "https://shop.example.com/"
        }
      },
      "CheckoutFromCartRequest": {
        "summary": "Convert the cart",
        "description": "Step 3: a checkout from the cart of step 2. Its lines, buyer, context and codes come from the cart.",
        "value": {
          "cart_id": "9a3f6c2e-5b18-4d47-8e9c-1f2a7b4d6e83"
        }
      },
      "CheckoutCreateRequest": {
        "summary": "A checkout directly from lines",
        "description": "Another buyer creates a checkout without a cart: one helmet, a buyer and a shipping address in one call. The address id `office` is only used to select it.",
        "value": {
          "line_items": [
            {
              "item": {
                "id": "4a6e2d9c-8b15-4f37-9c48-1e7a5b3d2f90"
              },
              "quantity": 1
            }
          ],
          "buyer": {
            "first_name": "Peter",
            "last_name": "Horváth",
            "email": "peter.horvath@example.com"
          },
          "context": {
            "address_country": "SK",
            "language": "sk"
          },
          "fulfillment": {
            "methods": [
              {
                "type": "shipping",
                "destinations": [
                  {
                    "id": "office",
                    "street_address": "Námestie SNP 5",
                    "address_locality": "Banská Bystrica",
                    "postal_code": "974 01",
                    "address_country": "SK",
                    "first_name": "Peter",
                    "last_name": "Horváth"
                  }
                ],
                "selected_destination_id": "office"
              }
            ]
          }
        }
      },
      "CheckoutUpdateRequest": {
        "summary": "Buyer, address, shipping option, one code",
        "description": "Step 4. `buyer` replaces the stored buyer, so the e-mail is sent again with the new fields. GLS is selected with an option id from step 3. Sending only JESEN10 drops LETO5 and its warning.",
        "value": {
          "buyer": {
            "first_name": "Jana",
            "last_name": "Nováková",
            "email": "jana.novakova@example.com",
            "phone_number": "+421 905 123 456"
          },
          "fulfillment": {
            "methods": [
              {
                "type": "shipping",
                "destinations": [
                  {
                    "id": "home",
                    "street_address": "Hlavná 12",
                    "address_locality": "Bratislava",
                    "postal_code": "811 01",
                    "address_country": "SK",
                    "first_name": "Jana",
                    "last_name": "Nováková"
                  }
                ],
                "selected_destination_id": "home",
                "groups": [
                  {
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [
              "JESEN10"
            ]
          }
        }
      },
      "CheckoutCompleteRequest": {
        "summary": "Empty body",
        "description": "Step 5. The body is ignored; a payment object would be ignored too.",
        "value": {}
      },
      "CheckoutIncomplete": {
        "summary": "Checkout created from the cart (201, incomplete)",
        "description": "The answer to CheckoutFromCartRequest. The checkout has its own lines (new line ids), the cart’s buyer, context and codes; JESEN10 is applied again and LETO5 warned about again. No address yet, so both shipping options are offered (no country filter) and none is selected: two `recoverable` errors keep it `incomplete`, so there is no `payment_required`. `expires_at` = now + 24 h.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "status": "incomplete",
          "currency": "EUR",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "total",
              "amount": 66036
            }
          ],
          "messages": [
            {
              "type": "warning",
              "code": "discount_code_combination_disallowed",
              "path": "$.discounts.codes[1]",
              "content": "Code 'LETO5' cannot be combined with 'JESEN10'"
            },
            {
              "type": "error",
              "code": "missing",
              "path": "$.fulfillment.methods[0].destinations",
              "content": "A shipping address is required",
              "severity": "recoverable"
            },
            {
              "type": "error",
              "code": "missing",
              "path": "$.fulfillment.methods[0].groups[0].selected_option_id",
              "content": "Choose a shipping option",
              "severity": "recoverable"
            }
          ],
          "links": [
            {
              "type": "terms_of_service",
              "url": "https://shop.example.com/obchodne-podmienky",
              "title": "Obchodné podmienky"
            },
            {
              "type": "privacy_policy",
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "title": "Ochrana osobných údajov"
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "groups": [
                  {
                    "id": "default",
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "description": "Doručenie na adresu do 1–2 pracovných dní",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ]
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "description": "Delivery in 2–3 business days",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ]
                      }
                    ],
                    "selected_option_id": null
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b",
          "expires_at": "2026-10-27T09:18:12.930Z"
        }
      },
      "CheckoutExistingForCart": {
        "summary": "The cart’s open checkout, answered again",
        "description": "POST /ucp/v1/checkout-sessions with the same `cart_id` again (HTTP **200**, not 201), or a GET of the checkout before step 4: the open checkout re-derived from the stored state. Write-time messages (the LETO5 warning) are not repeated; nothing in the new request is applied. `expires_at` is the stored one.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "status": "incomplete",
          "currency": "EUR",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "total",
              "amount": 66036
            }
          ],
          "messages": [
            {
              "type": "error",
              "code": "missing",
              "path": "$.fulfillment.methods[0].destinations",
              "content": "A shipping address is required",
              "severity": "recoverable"
            },
            {
              "type": "error",
              "code": "missing",
              "path": "$.fulfillment.methods[0].groups[0].selected_option_id",
              "content": "Choose a shipping option",
              "severity": "recoverable"
            }
          ],
          "links": [
            {
              "type": "terms_of_service",
              "url": "https://shop.example.com/obchodne-podmienky",
              "title": "Obchodné podmienky"
            },
            {
              "type": "privacy_policy",
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "title": "Ochrana osobných údajov"
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "groups": [
                  {
                    "id": "default",
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "description": "Doručenie na adresu do 1–2 pracovných dní",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ]
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "description": "Delivery in 2–3 business days",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ]
                      }
                    ],
                    "selected_option_id": null
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [
              "JESEN10",
              "LETO5"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b",
          "expires_at": "2026-10-27T09:18:12.930Z"
        }
      },
      "CheckoutCreatedDirect": {
        "summary": "Checkout created from lines (201, incomplete)",
        "description": "The answer to CheckoutCreateRequest: the address is complete and the shop ships to SK, so only the shipping option is missing. `discounts.codes` is empty (none sent).",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "b7d2e9a4-1c56-4e83-9f2b-6a4d8c1e3f75",
          "status": "incomplete",
          "currency": "EUR",
          "line_items": [
            {
              "id": "9c4f7a2e-6d18-4b39-a5c1-8e3f2d6b9a07",
              "item": {
                "id": "4a6e2d9c-8b15-4f37-9c48-1e7a5b3d2f90",
                "title": "Cyklistická prilba Lumen",
                "price": 5990
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 5990
                },
                {
                  "type": "total",
                  "amount": 5990
                }
              ]
            }
          ],
          "totals": [
            {
              "type": "subtotal",
              "amount": 5990
            },
            {
              "type": "total",
              "amount": 5990
            }
          ],
          "messages": [
            {
              "type": "error",
              "code": "missing",
              "path": "$.fulfillment.methods[0].groups[0].selected_option_id",
              "content": "Choose a shipping option",
              "severity": "recoverable"
            }
          ],
          "links": [
            {
              "type": "terms_of_service",
              "url": "https://shop.example.com/obchodne-podmienky",
              "title": "Obchodné podmienky"
            },
            {
              "type": "privacy_policy",
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "title": "Ochrana osobných údajov"
            }
          ],
          "buyer": {
            "first_name": "Peter",
            "last_name": "Horváth",
            "email": "peter.horvath@example.com"
          },
          "context": {
            "address_country": "SK",
            "language": "sk"
          },
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "line_item_ids": [
                  "9c4f7a2e-6d18-4b39-a5c1-8e3f2d6b9a07"
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "street_address": "Námestie SNP 5",
                    "address_locality": "Banská Bystrica",
                    "postal_code": "974 01",
                    "address_country": "SK",
                    "first_name": "Peter",
                    "last_name": "Horváth"
                  }
                ],
                "selected_destination_id": "destination",
                "groups": [
                  {
                    "id": "default",
                    "line_item_ids": [
                      "9c4f7a2e-6d18-4b39-a5c1-8e3f2d6b9a07"
                    ],
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "description": "Doručenie na adresu do 1–2 pracovných dní",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ]
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "description": "Delivery in 2–3 business days",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ]
                      }
                    ],
                    "selected_option_id": null
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [],
            "applied": []
          },
          "continue_url": "https://shop.example.com/ucp/continue/44e9cdc7dee1005696a98525ce10c6090ab8a7eb3654a490c538c5caf3989e39",
          "expires_at": "2026-10-27T10:02:44.207Z"
        }
      },
      "CheckoutRequiresEscalation": {
        "summary": "Ready: the buyer must continue on the shop",
        "description": "The answer to CheckoutUpdateRequest (step 4), and to a GET before the buyer has ordered. Nothing the platform can provide is missing: status `requires_escalation`, `payment_required` (`requires_buyer_input`) and `continue_url`. GLS 4.90 € is the `fulfillment` total: 718.80 − 58.44 + 4.90 = 665.26 €. The destination id came back as `destination`. Give `continue_url` to the buyer now.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "status": "requires_escalation",
          "currency": "EUR",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "fulfillment",
              "amount": 490
            },
            {
              "type": "total",
              "amount": 66526
            }
          ],
          "messages": [
            {
              "type": "error",
              "code": "payment_required",
              "content": "Payment is completed on the shop website — continue there to place the order",
              "severity": "requires_buyer_input"
            }
          ],
          "links": [
            {
              "type": "terms_of_service",
              "url": "https://shop.example.com/obchodne-podmienky",
              "title": "Obchodné podmienky"
            },
            {
              "type": "privacy_policy",
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "title": "Ochrana osobných údajov"
            }
          ],
          "buyer": {
            "first_name": "Jana",
            "last_name": "Nováková",
            "email": "jana.novakova@example.com",
            "phone_number": "+421 905 123 456"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "street_address": "Hlavná 12",
                    "address_locality": "Bratislava",
                    "postal_code": "811 01",
                    "address_country": "SK",
                    "first_name": "Jana",
                    "last_name": "Nováková"
                  }
                ],
                "selected_destination_id": "destination",
                "groups": [
                  {
                    "id": "default",
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "description": "Doručenie na adresu do 1–2 pracovných dní",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ]
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "description": "Delivery in 2–3 business days",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ]
                      }
                    ],
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [
              "JESEN10"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b",
          "expires_at": "2026-10-27T09:21:30.551Z"
        }
      },
      "CheckoutCompleteResponse": {
        "summary": "Complete changes nothing",
        "description": "POST …/complete (step 5): the checkout as it stands — still `requires_escalation` with `payment_required` and `continue_url`; `expires_at` is not extended. No order is placed through the API.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "status": "requires_escalation",
          "currency": "EUR",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "fulfillment",
              "amount": 490
            },
            {
              "type": "total",
              "amount": 66526
            }
          ],
          "messages": [
            {
              "type": "error",
              "code": "payment_required",
              "content": "Payment is completed on the shop website — continue there to place the order",
              "severity": "requires_buyer_input"
            }
          ],
          "links": [
            {
              "type": "terms_of_service",
              "url": "https://shop.example.com/obchodne-podmienky",
              "title": "Obchodné podmienky"
            },
            {
              "type": "privacy_policy",
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "title": "Ochrana osobných údajov"
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com",
            "last_name": "Nováková",
            "first_name": "Jana",
            "phone_number": "+421 905 123 456"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "last_name": "Nováková",
                    "first_name": "Jana",
                    "postal_code": "811 01",
                    "street_address": "Hlavná 12",
                    "address_country": "SK",
                    "address_locality": "Bratislava"
                  }
                ],
                "selected_destination_id": "destination",
                "groups": [
                  {
                    "id": "default",
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "description": "Doručenie na adresu do 1–2 pracovných dní",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ]
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "description": "Delivery in 2–3 business days",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ]
                      }
                    ],
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [
              "JESEN10"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b",
          "expires_at": "2026-10-27T09:21:30.551Z"
        }
      },
      "CheckoutCompleted": {
        "summary": "Completed by the buyer’s order",
        "description": "GET after the buyer opened `continue_url` and placed order SK2600417 on the shop (step 6). The body is the last answer the platform received (step 4) without `continue_url`, with `status: \"completed\"`, `messages: []` and `order` appended. It does not reflect what the buyer changed on the shop. “Completed” means placed, not paid.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "buyer": {
            "email": "jana.novakova@example.com",
            "last_name": "Nováková",
            "first_name": "Jana",
            "phone_number": "+421 905 123 456"
          },
          "links": [
            {
              "url": "https://shop.example.com/obchodne-podmienky",
              "type": "terms_of_service",
              "title": "Obchodné podmienky"
            },
            {
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "type": "privacy_policy",
              "title": "Ochrana osobných údajov"
            }
          ],
          "status": "completed",
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "fulfillment",
              "amount": 490
            },
            {
              "type": "total",
              "amount": 66526
            }
          ],
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "currency": "EUR",
          "messages": [],
          "discounts": {
            "codes": [
              "JESEN10"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "expires_at": "2026-10-27T09:21:30.551Z",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "price": 69900,
                "title": "Trek Marlin 5",
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ],
              "quantity": 1
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "price": 990,
                "title": "Fľaša na vodu 750 ml"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ],
              "quantity": 2
            }
          ],
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "groups": [
                  {
                    "id": "default",
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ],
                        "description": "Doručenie na adresu do 1–2 pracovných dní"
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ],
                        "description": "Delivery in 2–3 business days"
                      }
                    ],
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "last_name": "Nováková",
                    "first_name": "Jana",
                    "postal_code": "811 01",
                    "street_address": "Hlavná 12",
                    "address_country": "SK",
                    "address_locality": "Bratislava"
                  }
                ],
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "selected_destination_id": "destination"
              }
            ]
          },
          "order": {
            "id": "8e1c4f7a-2d95-4b36-a7e8-5c3f9b1d6a24",
            "label": "SK2600417",
            "permalink_url": "https://shop.example.com/order-confirmation?orderNumber=SK2600417&orderId=8e1c4f7a-2d95-4b36-a7e8-5c3f9b1d6a24"
          }
        }
      },
      "CheckoutAlreadyCompleted": {
        "summary": "Writing to a completed checkout",
        "description": "PUT or cancel on the checkout of step 6: nothing changes; the completed checkout comes back with a `checkout_completed` message. The order is never canceled through UCP.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "buyer": {
            "email": "jana.novakova@example.com",
            "last_name": "Nováková",
            "first_name": "Jana",
            "phone_number": "+421 905 123 456"
          },
          "links": [
            {
              "url": "https://shop.example.com/obchodne-podmienky",
              "type": "terms_of_service",
              "title": "Obchodné podmienky"
            },
            {
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "type": "privacy_policy",
              "title": "Ochrana osobných údajov"
            }
          ],
          "status": "completed",
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "fulfillment",
              "amount": 490
            },
            {
              "type": "total",
              "amount": 66526
            }
          ],
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "currency": "EUR",
          "messages": [
            {
              "type": "error",
              "code": "checkout_completed",
              "content": "This checkout is already completed",
              "severity": "unrecoverable"
            }
          ],
          "discounts": {
            "codes": [
              "JESEN10"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "expires_at": "2026-10-27T09:21:30.551Z",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "price": 69900,
                "title": "Trek Marlin 5",
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ],
              "quantity": 1
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "price": 990,
                "title": "Fľaša na vodu 750 ml"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ],
              "quantity": 2
            }
          ],
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "groups": [
                  {
                    "id": "default",
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ],
                        "description": "Doručenie na adresu do 1–2 pracovných dní"
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ],
                        "description": "Delivery in 2–3 business days"
                      }
                    ],
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "last_name": "Nováková",
                    "first_name": "Jana",
                    "postal_code": "811 01",
                    "street_address": "Hlavná 12",
                    "address_country": "SK",
                    "address_locality": "Bratislava"
                  }
                ],
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "selected_destination_id": "destination"
              }
            ]
          },
          "order": {
            "id": "8e1c4f7a-2d95-4b36-a7e8-5c3f9b1d6a24",
            "label": "SK2600417",
            "permalink_url": "https://shop.example.com/order-confirmation?orderNumber=SK2600417&orderId=8e1c4f7a-2d95-4b36-a7e8-5c3f9b1d6a24"
          }
        }
      },
      "CheckoutCanceled": {
        "summary": "Checkout canceled",
        "description": "POST …/cancel on the open checkout of step 4 (instead of the handoff), and every later GET: `status: \"canceled\"`, `messages: []`, no `continue_url`, the stored `expires_at`. A later PUT, complete or cancel adds `checkout_canceled`. An open checkout read or written after `expires_at` looks the same.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "status": "canceled",
          "currency": "EUR",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "title": "Trek Marlin 5",
                "price": 69900,
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "quantity": 1,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ]
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "title": "Fľaša na vodu 750 ml",
                "price": 990
              },
              "quantity": 2,
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ]
            }
          ],
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "fulfillment",
              "amount": 490
            },
            {
              "type": "total",
              "amount": 66526
            }
          ],
          "messages": [],
          "links": [
            {
              "type": "terms_of_service",
              "url": "https://shop.example.com/obchodne-podmienky",
              "title": "Obchodné podmienky"
            },
            {
              "type": "privacy_policy",
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "title": "Ochrana osobných údajov"
            }
          ],
          "buyer": {
            "email": "jana.novakova@example.com",
            "last_name": "Nováková",
            "first_name": "Jana",
            "phone_number": "+421 905 123 456"
          },
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "last_name": "Nováková",
                    "first_name": "Jana",
                    "postal_code": "811 01",
                    "street_address": "Hlavná 12",
                    "address_country": "SK",
                    "address_locality": "Bratislava"
                  }
                ],
                "selected_destination_id": "destination",
                "groups": [
                  {
                    "id": "default",
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "description": "Doručenie na adresu do 1–2 pracovných dní",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ]
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "description": "Delivery in 2–3 business days",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ]
                      }
                    ],
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ]
              }
            ]
          },
          "discounts": {
            "codes": [
              "JESEN10"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "expires_at": "2026-10-27T09:21:30.551Z"
        }
      },
      "CheckoutUpdateHandedOff": {
        "summary": "Writing after the handoff",
        "description": "A PUT after the buyer opened `continue_url` but before the order: the last answer, its values unchanged (served from storage, so its keys come in JSONB order), with its messages and a `handed_off` warning. The request was not applied. Only a PUT shows the handoff; a GET (and `complete`) returns the values of step 4.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            },
            "payment_handlers": {}
          },
          "id": "3d7b9e2a-6f14-4c58-9b3e-8a2f1c6d4e97",
          "buyer": {
            "email": "jana.novakova@example.com",
            "last_name": "Nováková",
            "first_name": "Jana",
            "phone_number": "+421 905 123 456"
          },
          "links": [
            {
              "url": "https://shop.example.com/obchodne-podmienky",
              "type": "terms_of_service",
              "title": "Obchodné podmienky"
            },
            {
              "url": "https://shop.example.com/ochrana-osobnych-udajov",
              "type": "privacy_policy",
              "title": "Ochrana osobných údajov"
            }
          ],
          "status": "requires_escalation",
          "totals": [
            {
              "type": "subtotal",
              "amount": 71880
            },
            {
              "type": "discount",
              "amount": -5844,
              "display_text": "JESEN10"
            },
            {
              "type": "fulfillment",
              "amount": 490
            },
            {
              "type": "total",
              "amount": 66526
            }
          ],
          "context": {
            "language": "sk",
            "address_country": "SK"
          },
          "currency": "EUR",
          "messages": [
            {
              "code": "payment_required",
              "type": "error",
              "content": "Payment is completed on the shop website — continue there to place the order",
              "severity": "requires_buyer_input"
            },
            {
              "type": "warning",
              "code": "handed_off",
              "content": "The buyer continued on the shop: the items are in the shop’s cart now and this session is no longer changed"
            }
          ],
          "discounts": {
            "codes": [
              "JESEN10"
            ],
            "applied": [
              {
                "code": "JESEN10",
                "title": "JESEN10",
                "amount": 5844,
                "method": "across"
              }
            ]
          },
          "expires_at": "2026-10-27T09:21:30.551Z",
          "line_items": [
            {
              "id": "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
              "item": {
                "id": "1e8a6c4f-2b93-4d71-9f05-6a3c8e2b1d47",
                "price": 69900,
                "title": "Trek Marlin 5",
                "image_url": "https://shop.example.com/api/public/uploads/c4d1e5a2-8b3f-4a6c-9e07-5f2d8a1b3c40/products/trek-marlin-5-modra.webp"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 69900
                },
                {
                  "type": "total",
                  "amount": 69900
                }
              ],
              "quantity": 1
            },
            {
              "id": "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49",
              "item": {
                "id": "b5f81c3d-6e49-4a2b-8d73-9c0e4f1a6b25",
                "price": 990,
                "title": "Fľaša na vodu 750 ml"
              },
              "totals": [
                {
                  "type": "subtotal",
                  "amount": 1980
                },
                {
                  "type": "total",
                  "amount": 1980
                }
              ],
              "quantity": 2
            }
          ],
          "fulfillment": {
            "methods": [
              {
                "id": "shipping",
                "type": "shipping",
                "groups": [
                  {
                    "id": "default",
                    "options": [
                      {
                        "id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75",
                        "title": "GLS kuriér",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 490
                          }
                        ],
                        "description": "Doručenie na adresu do 1–2 pracovných dní"
                      },
                      {
                        "id": "6b2d9f4e-3a17-4c68-9d5b-1f8e3a7c2b40",
                        "title": "Packeta – výdajné miesto",
                        "totals": [
                          {
                            "type": "total",
                            "amount": 290
                          }
                        ],
                        "description": "Delivery in 2–3 business days"
                      }
                    ],
                    "line_item_ids": [
                      "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                      "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                    ],
                    "selected_option_id": "0c5e8a3f-7b21-4d96-8f4c-9e2a6d1b3c75"
                  }
                ],
                "destinations": [
                  {
                    "id": "destination",
                    "last_name": "Nováková",
                    "first_name": "Jana",
                    "postal_code": "811 01",
                    "street_address": "Hlavná 12",
                    "address_country": "SK",
                    "address_locality": "Bratislava"
                  }
                ],
                "line_item_ids": [
                  "f6a3c8e1-9d27-4b54-8e6a-2c1f7b9d3a58",
                  "2e9d5b7a-4c83-4f16-a9b2-6d8e1c3f7a49"
                ],
                "selected_destination_id": "destination"
              }
            ]
          },
          "continue_url": "https://shop.example.com/ucp/continue/9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b"
        }
      },
      "CheckoutNotFound": {
        "summary": "Unknown checkout (HTTP 200)",
        "description": "Any checkout operation on an id that is not a UUID or belongs to another shop, and `POST /checkout-sessions` with an unknown `cart_id`. HTTP 200.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "status": "error",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "messages": [
            {
              "type": "error",
              "code": "not_found",
              "content": "Checkout session not found",
              "severity": "unrecoverable"
            }
          ],
          "continue_url": "https://shop.example.com/"
        }
      },
      "CheckoutFromHandedOffCart": {
        "summary": "Converting a cart the buyer already took to the shop (HTTP 200)",
        "description": "POST /checkout-sessions with the `cart_id` of a cart that was handed over (or one of whose checkouts was). No checkout is made; `continue_url` points at the shop’s cart page.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "status": "error",
            "capabilities": {
              "dev.ucp.shopping.checkout": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.fulfillment": [
                {
                  "version": "2026-04-08"
                }
              ],
              "dev.ucp.shopping.discount": [
                {
                  "version": "2026-04-08"
                }
              ]
            }
          },
          "messages": [
            {
              "type": "error",
              "code": "handed_off",
              "content": "The buyer continued on the shop: the items are in the shop’s cart — finish the purchase there",
              "severity": "unrecoverable"
            }
          ],
          "continue_url": "https://shop.example.com/cart"
        }
      },
      "ErrorCapabilityMissing": {
        "summary": "capabilities_incompatible (HTTP 200)",
        "description": "Any operation whose root capability your profile does not declare at 2026-04-08 — e.g. a cart call when the profile lists only the catalog capabilities, or any cart / checkout call on a shop in catalog mode. Nothing runs, no Idempotency-Key is used.",
        "value": {
          "ucp": {
            "version": "2026-04-08",
            "status": "error",
            "capabilities": {}
          },
          "messages": [
            {
              "type": "error",
              "code": "capabilities_incompatible",
              "content": "The platform and this business share no version of the capability this operation needs",
              "severity": "unrecoverable"
            }
          ],
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorMissingAgent": {
        "summary": "UCP-Agent missing or unusable",
        "description": "No `UCP-Agent` header, or one that fails the grammar or the URL rules. HTTP 400.",
        "value": {
          "code": "invalid_profile_url",
          "content": "The UCP-Agent header must carry profile=\"https://…\"",
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorVersionUnsupported": {
        "summary": "Your profile declares another protocol version",
        "description": "The fetched platform profile says `ucp.version: \"2026-01-11\"`. Older and newer versions are refused alike. HTTP 422.",
        "value": {
          "code": "version_unsupported",
          "content": "Protocol version 2026-01-11 is not supported. This business supports version 2026-04-08.",
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorProfileUnreachable": {
        "summary": "Your profile could not be fetched",
        "description": "A network error, a timeout, a redirect, any status other than 200, a body over 256 KiB, or a host resolving to a private address. Remembered for 60 s. HTTP 424.",
        "value": {
          "code": "profile_unreachable",
          "content": "Unable to fetch the platform profile",
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorProfileMalformed": {
        "summary": "Your profile is not a UCP profile",
        "description": "The profile is not JSON, has no `ucp` object, or its `ucp.version` is not a YYYY-MM-DD string. Remembered for 60 s. HTTP 422.",
        "value": {
          "code": "profile_malformed",
          "content": "The platform profile is not a valid UCP profile",
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorDiscoveryClientBudget": {
        "summary": "Too many new profiles from your IP",
        "description": "Your client (IPv4 address or IPv6 /64) already started 5 fetches of unknown profile URLs this minute. `Retry-After` = the rest of the one-minute window (at least 1 s). HTTP 503.",
        "value": {
          "code": "service_unavailable",
          "content": "Too many new platform profiles from this client, retry shortly",
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorDiscoveryBusy": {
        "summary": "Profile discovery busy",
        "description": "The shop’s server started 60 fetches of unknown profiles this minute. `Retry-After: 10`. HTTP 503.",
        "value": {
          "code": "service_unavailable",
          "content": "Platform profile discovery is busy, retry shortly",
          "continue_url": "https://shop.example.com/"
        }
      },
      "ErrorShopUnavailable": {
        "summary": "Shop temporarily unavailable",
        "description": "The company is deactivated or billing-locked, the shop lookup failed, or (handoff claim only) the session was busy. `Retry-After: 60`. HTTP 503.",
        "value": {
          "code": "service_unavailable",
          "content": "This shop is temporarily unavailable"
        }
      },
      "ErrorSessionBusy": {
        "summary": "Another request holds the session",
        "description": "Another request on the same cart or checkout is running and this one could not get its turn within 10 s, or 4 requests were already waiting (this request did not run) — or, rarely, another writer changed the session while this request ran (its result was not stored). The Idempotency-Key was released: retry the same request with the same key. `Retry-After: 1`. HTTP 503.",
        "value": {
          "code": "service_unavailable",
          "content": "Another request on this session is being processed — retry shortly"
        }
      },
      "ErrorIdempotencyConflict": {
        "summary": "Key reused for another request",
        "description": "The Idempotency-Key was already used (by your profile URL, on this shop) for another operation, path id or body — or the first request’s claim vanished while this one looked it up. HTTP 409.",
        "value": {
          "code": "idempotency_conflict",
          "content": "This Idempotency-Key was used for a different request"
        }
      },
      "ErrorIdempotencyInProgress": {
        "summary": "The same request is still running",
        "description": "A request with this key and the same body has not finished yet. `Retry-After: 2`. HTTP 409.",
        "value": {
          "code": "idempotency_conflict",
          "content": "A request with this Idempotency-Key is still being processed"
        }
      },
      "ErrorRateLimited": {
        "summary": "Rate limit of the operation",
        "description": "More than the operation’s per-minute limit from your IP (600 reads, 300 writes, 60 handoff). `Retry-After: 60`. HTTP 429.",
        "value": {
          "code": "rate_limited",
          "content": "Too many requests"
        }
      },
      "ErrorInvalidRequest": {
        "summary": "A body field with the wrong shape",
        "description": "E.g. `{\"line_items\":[{\"item\":{\"id\":\"…\"},\"quantity\":0}]}`. The `content` names the field. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "line_items[0].quantity must be a positive integer"
        }
      },
      "ErrorLineItemsRequired": {
        "summary": "line_items missing on a cart",
        "description": "PUT /ucp/v1/carts/{id} (or a create) without `line_items`. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "line_items must be an array"
        }
      },
      "ErrorUnknownCountry": {
        "summary": "Unrecognised destination country",
        "description": "The chosen shipping destination’s `address_country` is neither an alpha-2 / alpha-3 code nor a known country name (e.g. `\"Slovensko republic\"`). HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "fulfillment.methods[].destinations[0].address_country is not a recognised country; send an ISO 3166-1 alpha-2 code such as \"SK\""
        }
      },
      "ErrorInvalidIdempotencyKey": {
        "summary": "Idempotency-Key malformed",
        "description": "A key with a space, a non-ASCII character, more than 255 characters, or a header sent twice. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "Idempotency-Key is not valid"
        }
      },
      "ErrorSearchCategories": {
        "summary": "Category filter refused",
        "description": "`filters.categories` holding a value. Search by `query` (and `filters.price`) instead. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "filters.categories is not supported by this shop; search by query (and filters.price) instead"
        }
      },
      "ErrorSearchCursor": {
        "summary": "Cursor not valid",
        "description": "A `pagination.cursor` that this API did not issue (or longer than 40 characters). HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "pagination.cursor is not valid"
        }
      },
      "ErrorLookupNoIds": {
        "summary": "No ids",
        "description": "Lookup with `ids` missing or empty (or no JSON body). HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "ids must be a non-empty array"
        }
      },
      "ErrorLookupTooManyIds": {
        "summary": "More than 20 ids",
        "description": "Lookup with 21 or more `ids`. Note the status: 400, not 413. HTTP 400.",
        "value": {
          "code": "request_too_large",
          "content": "ids holds at most 20 identifiers"
        }
      },
      "ErrorProductIdRequired": {
        "summary": "No product id",
        "description": "POST /ucp/v1/catalog/product with `id` missing or blank. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "id is required"
        }
      },
      "ErrorMalformedJson": {
        "summary": "Body is not valid JSON",
        "description": "A body sent as `application/json` that does not parse (e.g. `{\"line_items\": [`), or a top-level JSON primitive. The body is parsed before routing, so this is the answer on every route a JSON body is sent to — also one that ignores its body. The library’s message is never echoed. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "The request is not valid"
        }
      },
      "ErrorUnsupportedCharset": {
        "summary": "Charset or encoding not supported",
        "description": "`Content-Type: application/json; charset=iso-8859-2` (a form-encoded body may use `utf-8` or `iso-8859-1`), or a `Content-Encoding` other than gzip, deflate, br or identity. HTTP 415.",
        "value": {
          "code": "invalid_request",
          "content": "The request is not valid"
        }
      },
      "ErrorNoBusinessOnHost": {
        "summary": "This host serves no UCP",
        "description": "An unknown host, a `*.shop.monokaido.com` subdomain, a domain without verified DNS or an active certificate, UCP switched off, the storefront off, an inactive or expired storefront key, or the e-shop module off — always the same answer. HTTP 404.",
        "value": {
          "code": "not_found",
          "content": "No UCP business on this host"
        }
      },
      "ErrorRouteNotFound": {
        "summary": "Unknown path or method",
        "description": "E.g. `POST /ucp/v1/nothing-here` or `DELETE /ucp/v1/catalog/search` (an unknown method is 404, not 405). HTTP 404.",
        "value": {
          "code": "not_found",
          "content": "Not found"
        }
      },
      "ErrorInternal": {
        "summary": "Unexpected failure",
        "description": "Anything unexpected (logged on the server; the message is never sent). Safe to retry a read; retry a write with the same Idempotency-Key. HTTP 500.",
        "value": {
          "code": "internal_error",
          "content": "Unexpected server error"
        }
      },
      "HandoffClaimRequest": {
        "summary": "The page’s claim",
        "description": "Posted by the handoff page’s own script with the browser’s storefront guest-cart id.",
        "value": {
          "sessionId": "5f0c2b1e-8d4a-4f6b-9c3e-2a1b0c9d8e7f"
        }
      },
      "HandoffClaimResponse": {
        "summary": "Continue to the shop’s checkout",
        "description": "The claim of a checkout session’s link: the lines and the code were added to that browser’s shop cart (or had been already); the page goes on to /checkout.",
        "value": {
          "redirect": "/checkout"
        }
      },
      "HandoffClaimInvalidSession": {
        "summary": "Bad guest-cart id",
        "description": "`sessionId` missing, shorter than 8 or longer than 128 characters, with other characters, or starting with `ucp_`; also malformed JSON. HTTP 400.",
        "value": {
          "code": "invalid_request",
          "content": "The request is not valid"
        }
      },
      "HandoffSessionGone": {
        "summary": "The session can no longer be handed over",
        "description": "Unknown or malformed token, or the session is completed, canceled or expired (also when it closed while waiting for its turn). HTTP 404.",
        "value": {
          "code": "not_found",
          "content": "Not found"
        }
      },
      "HandoffPage": {
        "summary": "The handoff page (200)",
        "description": "GET https://shop.example.com/ucp/continue/9bbd…780b for the open checkout of step 4. The page posts to its own URL and falls back to `/checkout`. The shop name is the company name. The inline script is the one the Content-Security-Policy hash allows.",
        "value": "<!doctype html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"referrer\" content=\"no-referrer\">\n<meta name=\"robots\" content=\"noindex, nofollow\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Horské bicykle s.r.o.</title>\n<style>body{font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;display:flex;min-height:100vh;align-items:center;justify-content:center;margin:0;color:#1f2937;background:#f8fafc}main{text-align:center;padding:24px}a{color:inherit}</style>\n</head>\n<body>\n<main>\n<p><strong>Horské bicykle s.r.o.</strong></p>\n<p>&#8230;</p>\n<noscript><p><a href=\"/checkout\">Horské bicykle s.r.o.</a></p></noscript>\n</main>\n<script type=\"application/json\" id=\"ucp-handoff\">{\"claimUrl\":\"/ucp/continue/9bbd3dedf887f93c6287fa7f4b8de141501155714c3b2050bb83551e36ec780b\",\"fallback\":\"/checkout\"}</script>\n<script>(function () {\n  var data = JSON.parse(document.getElementById('ucp-handoff').textContent);\n  var KEY = 'sf-cart';\n  var AUTH_KEY = 'sf-auth';\n  var MAX_ATTEMPTS = 3;\n  function uuid() {\n    if (window.crypto && crypto.randomUUID) return crypto.randomUUID();\n    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n      var r = (Math.random() * 16) | 0;\n      return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n    });\n  }\n  var stored = null;\n  try { stored = JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) {}\n  var state = stored && typeof stored === 'object' && stored.state && typeof stored.state === 'object' ? stored.state : {};\n  var sessionId = typeof state.sessionId === 'string' && state.sessionId ? state.sessionId : uuid();\n  var next = { state: Object.assign({}, state, { sessionId: sessionId, hasCart: true }), version: stored && typeof stored.version === 'number' ? stored.version : 0 };\n  try { localStorage.setItem(KEY, JSON.stringify(next)); } catch (e) {}\n  var token = null;\n  try {\n    var auth = JSON.parse(sessionStorage.getItem(AUTH_KEY) || 'null');\n    var t = auth && auth.state && auth.state.accessToken;\n    if (typeof t === 'string' && /^[A-Za-z0-9_.-]{16,4096}$/.test(t)) token = t;\n  } catch (e) {}\n  function go(path) { window.location.replace(path || data.fallback); }\n  function retry(attempt) {\n    if (attempt >= MAX_ATTEMPTS) { go(null); return; }\n    setTimeout(function () { claim(attempt + 1); }, 1000 * attempt);\n  }\n  function claim(attempt) {\n    var headers = { 'Content-Type': 'application/json' };\n    if (token) headers.Authorization = 'Bearer ' + token;\n    fetch(data.claimUrl, {\n      method: 'POST',\n      headers: headers,\n      credentials: 'omit',\n      body: JSON.stringify({ sessionId: sessionId })\n    }).then(function (r) {\n      if (r.ok) {\n        return r.json().then(function (j) {\n          go(j && typeof j.redirect === 'string' && /^[/](?:[A-Za-z0-9_-]+(?:[/][A-Za-z0-9_-]+)*)?$/.test(j.redirect) ? j.redirect : null);\n        }, function () { go(null); });\n      }\n      if (r.status >= 500 || r.status === 429) { retry(attempt); return; }\n      go(null);\n    }, function () { retry(attempt); });\n  }\n  claim(1);\n})();</script>\n</body>\n</html>"
      },
      "HandoffGonePage": {
        "summary": "The “gone” page (410)",
        "description": "The token is unknown or malformed, or the session is no longer open.",
        "value": "<!doctype html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"referrer\" content=\"no-referrer\">\n<meta name=\"robots\" content=\"noindex, nofollow\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Horské bicykle s.r.o.</title>\n<style>body{font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;display:flex;min-height:100vh;align-items:center;justify-content:center;margin:0;color:#1f2937;background:#f8fafc}main{text-align:center;padding:24px}a{color:inherit}</style>\n</head>\n<body>\n<main>\n<p><strong>Horské bicykle s.r.o.</strong></p>\n<p><a href=\"/\">Horské bicykle s.r.o.</a></p>\n</main>\n</body>\n</html>"
      },
      "HandoffNoBusinessPage": {
        "summary": "The page on a host without UCP (404)",
        "description": "The host serves no UCP (switched off, domain lost …): the same template with an empty shop name.",
        "value": "<!doctype html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"referrer\" content=\"no-referrer\">\n<meta name=\"robots\" content=\"noindex, nofollow\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title></title>\n<style>body{font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;display:flex;min-height:100vh;align-items:center;justify-content:center;margin:0;color:#1f2937;background:#f8fafc}main{text-align:center;padding:24px}a{color:inherit}</style>\n</head>\n<body>\n<main>\n<p><strong></strong></p>\n<p><a href=\"/\"></a></p>\n</main>\n</body>\n</html>"
      },
      "NginxTooManyRequests": {
        "summary": "Web server rate limit (HTML)",
        "description": "nginx’s own page, above 100 requests/s per client IP (burst 200): one budget for everything that IP sends to any shop host Monokaido serves (UCP calls, pages, images) and to the storefront API. No `Retry-After`, not JSON. Back off and retry. The footer may carry nginx’s version.",
        "value": "<html>\r\n<head><title>429 Too Many Requests</title></head>\r\n<body>\r\n<center><h1>429 Too Many Requests</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n"
      },
      "NginxPayloadTooLarge": {
        "summary": "Body over 1 MiB (HTML)",
        "description": "nginx’s own page for a request body over 1 MiB (the API itself reads JSON bodies up to 2 MiB once decompressed). Not JSON.",
        "value": "<html>\r\n<head><title>413 Request Entity Too Large</title></head>\r\n<body>\r\n<center><h1>413 Request Entity Too Large</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n"
      },
      "NginxBadGateway": {
        "summary": "API unreachable (HTML)",
        "description": "nginx’s own page while the API is down or restarting. Not JSON. Retry later.",
        "value": "<html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body>\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n"
      },
      "NginxGatewayTimeout": {
        "summary": "API did not answer within 60 s (HTML)",
        "description": "nginx’s own page when the API took longer than 60 s. A write may still have been applied: retry it with the same Idempotency-Key.",
        "value": "<html>\r\n<head><title>504 Gateway Time-out</title></head>\r\n<body>\r\n<center><h1>504 Gateway Time-out</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n"
      },
      "ErrorRequestTooLarge": {
        "summary": "Form-encoded body too large",
        "description": "An `application/x-www-form-urlencoded` body over 100 KiB (or with more than 1 000 fields), or a compressed JSON body over 2 MiB once decompressed — the API’s own 413, for a body that, as sent, passes the web server’s 1 MiB. HTTP 413.",
        "value": {
          "code": "request_too_large",
          "content": "Request body too large"
        }
      },
      "ErrorCrossOriginRejected": {
        "summary": "Refused by the cross-origin write gate",
        "description": "A POST or PUT that carries a Monokaido session cookie (`accessToken`, `refreshToken`, `platformAccessToken`, `platformRefreshToken`) and comes from a web origin the platform does not trust. HTTP 403.",
        "value": {
          "code": "invalid_request",
          "content": "The request is not valid"
        }
      }
    }
  }
}
