{
  "openapi": "3.1.0",
  "info": {
    "title": "Northern Fitness API",
    "version": "2026-11-06",
    "summary": "Public storefront, cart, agent checkout and customer account APIs for northernfitness.ca.",
    "description": "Northern Fitness (northernfitness.ca) is a Canadian online retailer of home and commercial gym equipment. This document describes the APIs that AI agents and developers can use with the store: read-only catalog and search endpoints, cart endpoints, the Universal Commerce Protocol (UCP) agent checkout over MCP, and the OAuth 2.0 protected Customer Account API. Catalog and cart endpoints need no authentication. Prices are in Canadian dollars (CAD); cart and product prices from the .js endpoints are integers in cents. The store runs on Shopify, so these endpoints follow Shopify's Ajax API and Customer Account API behaviour. Human-readable docs: https://www.northernfitness.ca/pages/developers",
    "termsOfService": "https://www.northernfitness.ca/policies/terms-of-service",
    "contact": {
      "name": "Northern Fitness support",
      "email": "support@northernfitness.ca",
      "url": "https://www.northernfitness.ca/pages/contact-us"
    }
  },
  "externalDocs": {
    "description": "Northern Fitness API and developer docs",
    "url": "https://www.northernfitness.ca/pages/developers"
  },
  "servers": [
    {
      "url": "https://www.northernfitness.ca",
      "description": "Northern Fitness storefront (CAD)"
    }
  ],
  "tags": [
    {
      "name": "Catalog",
      "description": "Read-only product, collection, search and recommendation data. No authentication."
    },
    {
      "name": "Cart",
      "description": "Session cart for the current browser or client (cart cookie). No authentication."
    },
    {
      "name": "Agent checkout",
      "description": "Universal Commerce Protocol (UCP) discovery and MCP endpoint for agent-driven catalog search, carts and checkout."
    },
    {
      "name": "Customer account",
      "description": "Signed-in customer data (orders, addresses, profile). OAuth 2.0 authorization code flow with PKCE and named scopes."
    }
  ],
  "security": [],
  "paths": {
    "/products.json": {
      "get": {
        "operationId": "listProducts",
        "tags": [
          "Catalog"
        ],
        "summary": "List products",
        "description": "Returns published products in pages of up to 250, newest first. Use page to paginate until an empty products array is returned.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Products per page (1 to 250).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number, starting at 1.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "products"
                  ],
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CatalogProduct"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/{handle}.js": {
      "get": {
        "operationId": "getProduct",
        "tags": [
          "Catalog"
        ],
        "summary": "Get a product by handle",
        "description": "Returns one product with its variants, prices in cents (CAD), availability and images. The handle is the last part of the product URL, for example orion-ruck-plates for /products/orion-ruck-plates.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "Product handle (URL slug).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9-]*$"
            },
            "example": "orion-ruck-plates"
          }
        ],
        "responses": {
          "200": {
            "description": "The product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/collections/{handle}/products.json": {
      "get": {
        "operationId": "listCollectionProducts",
        "tags": [
          "Catalog"
        ],
        "summary": "List products in a collection",
        "description": "Returns published products in one collection, such as dumbbells, benches or a brand like rep-fitness. Returns an empty array when the collection does not exist or has no products.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "Collection handle, for example dumbbells.",
            "schema": {
              "type": "string"
            },
            "example": "dumbbells"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Products per page (1 to 250).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number, starting at 1.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Products in the collection.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "products"
                  ],
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CatalogProduct"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/search/suggest.json": {
      "get": {
        "operationId": "searchProducts",
        "tags": [
          "Catalog"
        ],
        "summary": "Search products",
        "description": "Predictive search across products (and optionally collections, pages and articles). Best for finding products by name, brand or category, for example 'adjustable bench' or 'REP Fitness rack'.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search terms.",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "adjustable bench"
          },
          {
            "name": "resources[type]",
            "in": "query",
            "description": "Comma-separated resource types to return.",
            "schema": {
              "type": "string",
              "default": "product",
              "example": "product,collection"
            }
          },
          {
            "name": "resources[limit]",
            "in": "query",
            "description": "Results per type (1 to 10).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchSuggestions"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/recommendations/products.json": {
      "get": {
        "operationId": "getProductRecommendations",
        "tags": [
          "Catalog"
        ],
        "summary": "Get related or complementary products",
        "description": "Returns products related to (intent=related) or bought with (intent=complementary) a given product.",
        "parameters": [
          {
            "name": "product_id",
            "in": "query",
            "required": true,
            "description": "Numeric product ID from getProduct.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of products (1 to 10).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 10
            }
          },
          {
            "name": "intent",
            "in": "query",
            "description": "related or complementary.",
            "schema": {
              "type": "string",
              "enum": [
                "related",
                "complementary"
              ],
              "default": "related"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recommended products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/cart.js": {
      "get": {
        "operationId": "getCart",
        "tags": [
          "Cart"
        ],
        "summary": "Get the current cart",
        "description": "Returns the cart tied to the cart cookie sent with the request. A new empty cart is returned when there is no cookie.",
        "responses": {
          "200": {
            "description": "The cart.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/cart/add.js": {
      "post": {
        "operationId": "addToCart",
        "tags": [
          "Cart"
        ],
        "summary": "Add items to the cart",
        "description": "Adds one or more product variants to the cart. Use variant IDs from getProduct. Returns the added line items.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddToCartRequest"
              },
              "example": {
                "items": [
                  {
                    "id": 41047281434673,
                    "quantity": 1
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Added line items.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CartLine"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/cart/change.js": {
      "post": {
        "operationId": "changeCartLine",
        "tags": [
          "Cart"
        ],
        "summary": "Change the quantity of one cart line",
        "description": "Sets the quantity of a single cart line identified by its line item key or variant ID. Quantity 0 removes the line. Returns the full cart.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangeCartLineRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated cart.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/cart/update.js": {
      "post": {
        "operationId": "updateCart",
        "tags": [
          "Cart"
        ],
        "summary": "Update several cart quantities or the cart note",
        "description": "Sets quantities for several variants at once, keyed by variant ID, and optionally the cart note. Returns the full cart.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCartRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated cart.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/cart/clear.js": {
      "post": {
        "operationId": "clearCart",
        "tags": [
          "Cart"
        ],
        "summary": "Remove all items from the cart",
        "description": "Empties the cart and returns it.",
        "responses": {
          "200": {
            "description": "The empty cart.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/.well-known/ucp": {
      "get": {
        "operationId": "getUcpProfile",
        "tags": [
          "Agent checkout"
        ],
        "summary": "Get the UCP profile",
        "description": "Universal Commerce Protocol discovery document: supported versions, services, transports, MCP endpoint and capabilities (catalog search, carts, checkout).",
        "responses": {
          "200": {
            "description": "UCP profile.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ucp"
                  ],
                  "properties": {
                    "ucp": {
                      "type": "object",
                      "description": "Profile as defined by https://ucp.dev",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/ucp/mcp": {
      "post": {
        "operationId": "callUcpMcp",
        "tags": [
          "Agent checkout"
        ],
        "summary": "Call the UCP shopping MCP server",
        "description": "Model Context Protocol (Streamable HTTP, JSON-RPC 2.0) endpoint for agent shopping. Use tools/list to discover tools, then tools/call. Tools include search_catalog, lookup_catalog, get_product, create_cart, update_cart, get_cart, create_checkout, update_checkout, complete_checkout (buyer-authorized only), get_order, search_locations and ask_business.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/list"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result or JSON-RPC error object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/graphql": {
      "servers": [
        {
          "url": "https://shopify.com/26470285361/account/customer/api/2026-10",
          "description": "Customer Account API, current version (see https://www.northernfitness.ca/.well-known/customer-account-api)"
        }
      ],
      "post": {
        "operationId": "queryCustomerAccount",
        "tags": [
          "Customer account"
        ],
        "summary": "Query the signed-in customer's account",
        "description": "GraphQL endpoint for the signed-in customer's profile, addresses and order history. Requires an OAuth 2.0 access token obtained with the authorization code flow and PKCE. Request the customer-account-api:full scope.",
        "security": [
          {
            "customerAccountOAuth": [
              "openid",
              "email",
              "customer-account-api:full"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GraphQLRequest"
              },
              "example": {
                "query": "query { customer { firstName lastName orders(first: 5) { nodes { name totalPrice { amount currencyCode } } } } }"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GraphQL response. Field errors are returned in the errors array.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GraphQLResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/mcp": {
      "servers": [
        {
          "url": "https://shopify.com/26470285361/account/customer/api",
          "description": "Customer Account MCP server"
        }
      ],
      "post": {
        "operationId": "callCustomerAccountMcp",
        "tags": [
          "Customer account"
        ],
        "summary": "Call the Customer Account MCP server",
        "description": "MCP (JSON-RPC 2.0) access to the signed-in customer's orders and account. Requires an OAuth 2.0 access token with the customer-account-mcp-api:full scope.",
        "security": [
          {
            "customerAccountOAuth": [
              "openid",
              "customer-account-mcp-api:full"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result or error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "customerAccountOAuth": {
        "type": "oauth2",
        "description": "Shopify customer accounts for northernfitness.ca. Authorization code flow with PKCE (S256). Discovery: https://www.northernfitness.ca/.well-known/openid-configuration",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://shopify.com/authentication/26470285361/oauth/authorize",
            "tokenUrl": "https://shopify.com/authentication/26470285361/oauth/token",
            "refreshUrl": "https://shopify.com/authentication/26470285361/oauth/token",
            "scopes": {
              "openid": "Sign the customer in and return an ID token.",
              "email": "Read the customer's email address.",
              "customer-account-api:full": "Read and update the customer's profile, addresses and orders through the Customer Account API.",
              "customer-account-mcp-api:full": "Use the Customer Account MCP server on the customer's behalf.",
              "dev.ucp.shopping.checkout:manage": "Create and manage UCP checkouts on the customer's behalf.",
              "dev.ucp.shopping.catalog.search:read": "Search the catalog through UCP as the customer."
            }
          }
        }
      },
      "customerAccountOIDC": {
        "type": "openIdConnect",
        "openIdConnectUrl": "https://www.northernfitness.ca/.well-known/openid-configuration",
        "description": "OpenID Connect discovery for the same customer account login."
      }
    },
    "responses": {
      "Error": {
        "description": "Request error. The body explains the problem and how to fix it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No published resource matches the handle or ID. Check the handle with searchProducts."
      },
      "RateLimited": {
        "description": "Too many requests. Wait for the number of seconds in Retry-After, then retry.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Error body returned by catalog and cart endpoints.",
        "required": [
          "status",
          "message"
        ],
        "properties": {
          "status": {
            "type": "integer",
            "description": "HTTP status code.",
            "example": 422
          },
          "message": {
            "type": "string",
            "description": "Short error category.",
            "example": "Cart Error"
          },
          "description": {
            "type": "string",
            "description": "What went wrong and how to fix it.",
            "example": "Cannot find variant"
          }
        }
      },
      "Money": {
        "type": "integer",
        "description": "Amount in cents (CAD). 129900 means $1,299.00."
      },
      "Variant": {
        "type": "object",
        "required": [
          "id",
          "price",
          "available"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Variant ID used in cart requests."
          },
          "title": {
            "type": "string"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "price": {
            "$ref": "#/components/schemas/Money"
          },
          "compare_at_price": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Regular price in cents when on sale."
          },
          "available": {
            "type": "boolean",
            "description": "True when the variant can be ordered."
          },
          "option1": {
            "type": [
              "string",
              "null"
            ]
          },
          "option2": {
            "type": [
              "string",
              "null"
            ]
          },
          "option3": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Product": {
        "type": "object",
        "required": [
          "id",
          "title",
          "handle",
          "variants"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Product description (HTML)."
          },
          "vendor": {
            "type": "string",
            "description": "Brand, for example REP Fitness or Orion."
          },
          "type": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "price": {
            "$ref": "#/components/schemas/Money"
          },
          "price_min": {
            "$ref": "#/components/schemas/Money"
          },
          "price_max": {
            "$ref": "#/components/schemas/Money"
          },
          "compare_at_price": {
            "type": [
              "integer",
              "null"
            ]
          },
          "available": {
            "type": "boolean"
          },
          "url": {
            "type": "string",
            "description": "Relative product URL."
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri-reference"
            }
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            }
          }
        }
      },
      "CatalogProduct": {
        "type": "object",
        "description": "Product as returned by the .json catalog endpoints (prices are decimal strings in CAD).",
        "required": [
          "id",
          "title",
          "handle"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "body_html": {
            "type": "string"
          },
          "vendor": {
            "type": "string"
          },
          "product_type": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "variants": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "title": {
                  "type": "string"
                },
                "sku": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "price": {
                  "type": "string",
                  "example": "1299.00"
                },
                "compare_at_price": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "available": {
                  "type": "boolean"
                }
              }
            }
          },
          "images": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "src": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          }
        }
      },
      "SearchSuggestions": {
        "type": "object",
        "properties": {
          "resources": {
            "type": "object",
            "properties": {
              "results": {
                "type": "object",
                "properties": {
                  "products": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "title": {
                          "type": "string"
                        },
                        "handle": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string"
                        },
                        "vendor": {
                          "type": "string"
                        },
                        "price": {
                          "type": "string"
                        },
                        "available": {
                          "type": "boolean"
                        },
                        "image": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  },
                  "collections": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "title": {
                          "type": "string"
                        },
                        "handle": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CartLine": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Line item key, used by changeCartLine."
          },
          "id": {
            "type": "integer"
          },
          "variant_id": {
            "type": "integer"
          },
          "product_id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantity": {
            "type": "integer"
          },
          "price": {
            "$ref": "#/components/schemas/Money"
          },
          "line_price": {
            "$ref": "#/components/schemas/Money"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "Cart": {
        "type": "object",
        "required": [
          "token",
          "item_count",
          "items",
          "total_price",
          "currency"
        ],
        "properties": {
          "token": {
            "type": "string"
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "item_count": {
            "type": "integer"
          },
          "total_price": {
            "$ref": "#/components/schemas/Money"
          },
          "currency": {
            "type": "string",
            "example": "CAD"
          },
          "requires_shipping": {
            "type": "boolean"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CartLine"
            }
          }
        }
      },
      "AddToCartRequest": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": [
                "id",
                "quantity"
              ],
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "Variant ID."
                },
                "quantity": {
                  "type": "integer",
                  "minimum": 1
                },
                "properties": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  },
                  "description": "Optional line item properties."
                }
              }
            }
          }
        }
      },
      "ChangeCartLineRequest": {
        "type": "object",
        "required": [
          "quantity"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Line item key or variant ID."
          },
          "line": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based line number, as an alternative to id."
          },
          "quantity": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "UpdateCartRequest": {
        "type": "object",
        "properties": {
          "updates": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Map of variant ID to quantity."
          },
          "note": {
            "type": "string"
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string"
            ]
          },
          "method": {
            "type": "string",
            "description": "MCP method, for example tools/list or tools/call."
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string",
              "null"
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer",
                "example": -32601
              },
              "message": {
                "type": "string",
                "example": "Method not found"
              },
              "data": {}
            }
          }
        }
      },
      "GraphQLRequest": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string"
          },
          "variables": {
            "type": "object",
            "additionalProperties": true
          },
          "operationName": {
            "type": "string"
          }
        }
      },
      "GraphQLResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string"
                },
                "extensions": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    }
  }
}