{
  "openapi": "3.1.0",
  "info": {
    "title": "VERVE Fitness public storefront API",
    "version": "2026-10-13",
    "summary": "Read the VERVE Fitness gym equipment catalog: products, prices, stock, collections, search and recommendations.",
    "description": "VERVE Fitness sells commercial and home gym equipment in Australia from https://www.vervefitness.com.au. This document describes the public, read-only JSON endpoints that the store (hosted on Shopify) answers on its own domain, plus the agent discovery files and Shopify's Universal Commerce Protocol (UCP) MCP endpoint for cart and checkout.\n\nWhen to use it: finding gym equipment for an Australian buyer, comparing models, reading specs, prices and stock, and checking which attachments suit which rack. For commercial fit-out quotes, send the buyer to https://www.vervefitness.com.au/pages/commercial-gym-fitouts or sales@vervefitness.com.au.\n\nNo sign-up and no API key are needed for the catalog endpoints. There is no sandbox: everything here is live store data. Prices are in AUD and include GST unless a page says ex GST. The product page is authoritative for price and stock.\n\nErrors: search and recommendation endpoints return JSON {status, message, description}; paging past the limit returns JSON {errors}; single product and collection lookups return 404 with an empty body; the MCP endpoint returns JSON-RPC 2.0 errors.\n\nKnown issue (Shopify platform, October 2026): product, collection and content pages requested with Accept: text/markdown return 404. Request text/html or use these JSON endpoints instead.",
    "contact": {
      "name": "VERVE Fitness",
      "email": "team@vervefitness.com.au",
      "url": "https://www.vervefitness.com.au/pages/developers"
    }
  },
  "externalDocs": {
    "description": "Developer and AI agent guide",
    "url": "https://www.vervefitness.com.au/pages/developers"
  },
  "servers": [
    {
      "url": "https://www.vervefitness.com.au",
      "description": "Live store (Australia, AUD)"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "catalog",
      "description": "Products, variants, prices, stock and collections."
    },
    {
      "name": "search",
      "description": "Keyword search and product recommendations."
    },
    {
      "name": "discovery",
      "description": "Files that tell AI agents what the store is and how to call it."
    },
    {
      "name": "commerce",
      "description": "Cart, checkout and orders through Shopify's Universal Commerce Protocol (UCP)."
    }
  ],
  "paths": {
    "/products.json": {
      "get": {
        "operationId": "listProducts",
        "tags": [
          "catalog"
        ],
        "summary": "List all published products",
        "description": "Returns published products with variants, prices (AUD, as strings such as \"4699.00\"), stock flags and images. Use paging to walk the full catalog.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Items per page. Maximum 250. page multiplied by limit may not exceed 25,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "products"
                  ],
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "page multiplied by limit exceeds 25,000.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagingError"
                }
              }
            }
          }
        }
      }
    },
    "/products/{handle}.json": {
      "get": {
        "operationId": "getProduct",
        "tags": [
          "catalog"
        ],
        "summary": "Get one product by handle",
        "description": "Returns one product with every variant, its SKU, price, compare-at price, weight and barcode. The handle is the last part of the product URL.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "URL handle, for example power-racks or tori-functional-trainer-rack.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The product.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "product"
                  ],
                  "properties": {
                    "product": {
                      "$ref": "#/components/schemas/Product"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found. Shopify returns an empty body for this endpoint."
          }
        }
      }
    },
    "/collections.json": {
      "get": {
        "operationId": "listCollections",
        "tags": [
          "catalog"
        ],
        "summary": "List product collections",
        "description": "Returns collections (categories such as power-racks, functional-trainers, weight-plates) with product counts.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Items per page. Maximum 250. page multiplied by limit may not exceed 25,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of collections.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "collections"
                  ],
                  "properties": {
                    "collections": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Collection"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "page multiplied by limit exceeds 25,000.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagingError"
                }
              }
            }
          }
        }
      }
    },
    "/collections/{handle}.json": {
      "get": {
        "operationId": "getCollection",
        "tags": [
          "catalog"
        ],
        "summary": "Get one collection by handle",
        "description": "Returns one collection's title, description and product count.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "URL handle, for example power-racks or tori-functional-trainer-rack.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The collection.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "collection"
                  ],
                  "properties": {
                    "collection": {
                      "$ref": "#/components/schemas/Collection"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found. Shopify returns an empty body for this endpoint."
          }
        }
      }
    },
    "/collections/{handle}/products.json": {
      "get": {
        "operationId": "listCollectionProducts",
        "tags": [
          "catalog"
        ],
        "summary": "List the products in a collection",
        "description": "Returns the products in one collection, in the collection's sort order. An unknown handle returns 200 with an empty products array.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "URL handle, for example power-racks or tori-functional-trainer-rack.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Items per page. Maximum 250. page multiplied by limit may not exceed 25,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "products"
                  ],
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "page multiplied by limit exceeds 25,000.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagingError"
                }
              }
            }
          }
        }
      }
    },
    "/search/suggest.json": {
      "get": {
        "operationId": "searchProducts",
        "tags": [
          "search"
        ],
        "summary": "Search products by keyword",
        "description": "Predictive search across the catalog. Returns matching products with price range, availability and URL.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search words, for example power rack or 20kg barbell.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "resources",
            "in": "query",
            "required": false,
            "style": "deepObject",
            "explode": true,
            "description": "What to search and how many results. Sent as resources[type]=product&resources[limit]=10.",
            "schema": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "Comma-separated: product, collection, page, article, query.",
                  "default": "product"
                },
                "limit": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10,
                  "default": 10
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResult"
                }
              }
            }
          },
          "422": {
            "description": "Missing or invalid parameter. The body says which parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/recommendations/products.json": {
      "get": {
        "operationId": "getProductRecommendations",
        "tags": [
          "search"
        ],
        "summary": "Get products related to, or that go with, a product",
        "description": "Returns related products (alternatives) or complementary products (things bought with it). Prices here are integers in cents.",
        "parameters": [
          {
            "name": "product_id",
            "in": "query",
            "required": true,
            "description": "Numeric product id from getProduct or listProducts.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many products to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 10
            }
          },
          {
            "name": "intent",
            "in": "query",
            "required": false,
            "description": "related for alternatives, complementary for add-ons.",
            "schema": {
              "type": "string",
              "enum": [
                "related",
                "complementary"
              ],
              "default": "related"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recommended products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "products"
                  ],
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RecommendedProduct"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found. The body explains what was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/ucp": {
      "get": {
        "operationId": "getUcpProfile",
        "tags": [
          "discovery",
          "commerce"
        ],
        "summary": "Get the store's Universal Commerce Protocol profile",
        "description": "Machine-readable list of the store's commerce services (MCP endpoint), capabilities (catalog, cart, checkout, orders, discounts) and payment handlers. Published by Shopify.",
        "responses": {
          "200": {
            "description": "The UCP profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UcpProfile"
                }
              }
            }
          }
        }
      }
    },
    "/agents.md": {
      "get": {
        "operationId": "getAgentInstructions",
        "tags": [
          "discovery"
        ],
        "summary": "Get Shopify's agent instructions for this store",
        "description": "Markdown instructions for AI agents: the Shop skill, UCP checkout and browser tools.",
        "responses": {
          "200": {
            "description": "Agent instructions.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Get VERVE's summary for AI assistants",
        "description": "Markdown summary of who VERVE is, when to use it, product ranges, reference specs and accuracy notes.",
        "responses": {
          "200": {
            "description": "The llms.txt file.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/ucp/mcp": {
      "post": {
        "operationId": "callCommerceMcp",
        "tags": [
          "commerce"
        ],
        "summary": "Call Shopify's commerce MCP server (JSON-RPC 2.0)",
        "description": "Model Context Protocol server run by Shopify for this store. Methods: initialize, tools/list, tools/call. Tools: search_catalog, lookup_catalog, get_product, create_cart, get_cart, update_cart, cancel_cart, create_checkout, get_checkout, update_checkout, complete_checkout, cancel_checkout, get_order. Every tools/call must send the agent's UCP profile URL in arguments.meta['ucp-agent'].profile, otherwise the server answers 422 with error code -32001 (invalid_profile_url). Prices in tool results are integers in minor units (cents).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              },
              "examples": {
                "toolsList": {
                  "summary": "List tools",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "tools/list",
                    "params": {}
                  }
                },
                "searchCatalog": {
                  "summary": "Search the catalog",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "tools/call",
                    "params": {
                      "name": "search_catalog",
                      "arguments": {
                        "meta": {
                          "ucp-agent": {
                            "profile": "https://your-agent.example/.well-known/ucp"
                          }
                        },
                        "catalog": {
                          "query": "power rack",
                          "context": {
                            "address_country": "AU",
                            "currency": "AUD"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "422": {
            "description": "JSON-RPC error, for example a missing agent profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Error body used by search and recommendations.",
        "required": [
          "status",
          "message",
          "description"
        ],
        "properties": {
          "status": {
            "type": "integer",
            "examples": [
              422
            ]
          },
          "message": {
            "type": "string",
            "examples": [
              "Invalid parameter error"
            ]
          },
          "description": {
            "type": "string",
            "examples": [
              "param is missing or the value is empty: q"
            ]
          }
        }
      },
      "PagingError": {
        "type": "object",
        "required": [
          "errors"
        ],
        "properties": {
          "errors": {
            "type": "string",
            "examples": [
              "Page * Limit exceeds the 25000 limit."
            ]
          }
        }
      },
      "Image": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "src": {
            "type": "string",
            "format": "uri"
          },
          "alt": {
            "type": [
              "string",
              "null"
            ]
          },
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "position": {
            "type": "integer"
          }
        }
      },
      "Variant": {
        "type": "object",
        "required": [
          "id",
          "title",
          "price"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "product_id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "price": {
            "type": "string",
            "description": "AUD including GST, for example \"4699.00\"."
          },
          "compare_at_price": {
            "type": [
              "string",
              "null"
            ],
            "description": "Previous price when on sale; \"0.00\" or null when not on sale."
          },
          "available": {
            "type": "boolean",
            "description": "In stock or available to order. Present on list endpoints."
          },
          "option1": {
            "type": [
              "string",
              "null"
            ]
          },
          "option2": {
            "type": [
              "string",
              "null"
            ]
          },
          "option3": {
            "type": [
              "string",
              "null"
            ]
          },
          "grams": {
            "type": "integer"
          },
          "weight": {
            "type": "number"
          },
          "weight_unit": {
            "type": "string"
          },
          "barcode": {
            "type": [
              "string",
              "null"
            ]
          },
          "requires_shipping": {
            "type": "boolean"
          },
          "taxable": {
            "type": "boolean"
          }
        }
      },
      "Product": {
        "type": "object",
        "required": [
          "id",
          "title",
          "handle",
          "variants"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "body_html": {
            "type": [
              "string",
              "null"
            ],
            "description": "Product description and specs as HTML."
          },
          "vendor": {
            "type": "string"
          },
          "product_type": {
            "type": "string"
          },
          "tags": {
            "description": "Array on list endpoints, comma-separated string on getProduct.",
            "type": [
              "array",
              "string"
            ],
            "items": {
              "type": "string"
            }
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "values": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            }
          },
          "images": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Image"
            }
          }
        }
      },
      "Collection": {
        "type": "object",
        "required": [
          "id",
          "title",
          "handle"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "products_count": {
            "type": "integer"
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "image": {
            "type": [
              "object",
              "null"
            ]
          }
        }
      },
      "SearchProduct": {
        "type": "object",
        "required": [
          "id",
          "title",
          "handle",
          "url",
          "price"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "price": {
            "type": "string",
            "description": "Lowest variant price, AUD."
          },
          "price_min": {
            "type": "string"
          },
          "price_max": {
            "type": "string"
          },
          "available": {
            "type": "boolean"
          },
          "vendor": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "image": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SearchResult": {
        "type": "object",
        "required": [
          "resources"
        ],
        "properties": {
          "resources": {
            "type": "object",
            "properties": {
              "results": {
                "type": "object",
                "properties": {
                  "products": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/SearchProduct"
                    }
                  },
                  "collections": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "pages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "articles": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "queries": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "RecommendedProduct": {
        "type": "object",
        "required": [
          "id",
          "title",
          "handle",
          "price"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "price": {
            "type": "integer",
            "description": "Lowest variant price in cents (AUD)."
          },
          "price_min": {
            "type": "integer"
          },
          "price_max": {
            "type": "integer"
          },
          "available": {
            "type": "boolean"
          },
          "vendor": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "featured_image": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "UcpProfile": {
        "type": "object",
        "required": [
          "ucp"
        ],
        "properties": {
          "ucp": {
            "type": "object",
            "properties": {
              "version": {
                "type": "string"
              },
              "services": {
                "type": "object"
              },
              "capabilities": {
                "type": "object"
              },
              "payment_handlers": {
                "type": "object"
              }
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string"
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "initialize",
              "tools/list",
              "tools/call"
            ]
          },
          "params": {
            "type": "object"
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string"
            ]
          },
          "result": {
            "type": "object"
          },
          "error": {
            "$ref": "#/components/schemas/JsonRpcError"
          }
        }
      },
      "JsonRpcErrorResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "error"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string",
              "null"
            ]
          },
          "error": {
            "$ref": "#/components/schemas/JsonRpcError"
          }
        }
      },
      "JsonRpcError": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "examples": [
              -32001
            ]
          },
          "message": {
            "type": "string",
            "examples": [
              "UCP discovery failed"
            ]
          },
          "data": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "invalid_profile_url"
                ]
              },
              "content": {
                "type": "string"
              },
              "continue_url": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}
