{
  "openapi": "3.1.0",
  "info": {
    "title": "TUKD Concealment Storefront Read API",
    "version": "2026-09-02",
    "summary": "Anonymous read access to the TUKD Concealment holster catalog.",
    "description": "TUKD Concealment publishes its catalog as JSON so AI agents, shopping assistants and developers can answer fitment, price and availability questions without scraping HTML.\n\nEvery operation in this document is public: no API key, no OAuth token, no signup, no sandbox request. Send an ordinary HTTP GET.\n\nThis document is served at https://www.tukdconcealment.com/openapi.json (a 301 to the theme asset that holds it) and is linked from /llms.txt, /agents.md and /pages/for-agents.\n\nTransacting (cart and checkout) is not part of this REST surface. It is done over the Model Context Protocol server described in the `x-mcp` extension below and at /agents.md.\n\nKnown quirks of the underlying Shopify storefront, documented here because agents hit them:\n- An unknown product handle returns HTTP 404 with `Content-Type: application/json` and a zero-length body, not a JSON error object.\n- An unknown collection handle returns HTTP 200 with `{\"products\": []}` rather than a 404. Do not treat an empty array as proof the collection exists.\n- `limit` is capped at 250 by the platform. Values above 250 are clamped, not rejected. The full TUKD catalog is 23 products, so one request returns everything.",
    "contact": {
      "name": "TUKD Concealment Support",
      "email": "Support@TukdConcealment.com",
      "url": "https://www.tukdconcealment.com/pages/for-agents"
    },
    "termsOfService": "https://www.tukdconcealment.com/policies/terms-of-service"
  },
  "servers": [
    { "url": "https://www.tukdconcealment.com", "description": "Production storefront" }
  ],
  "security": [],
  "externalDocs": {
    "description": "Human-readable agent and developer guide",
    "url": "https://www.tukdconcealment.com/pages/for-agents"
  },
  "x-agent-index": {
    "llms_txt": "https://www.tukdconcealment.com/llms.txt",
    "llms_full_txt": "https://www.tukdconcealment.com/llms-full.txt",
    "agents_md": "https://www.tukdconcealment.com/agents.md",
    "openapi": "https://www.tukdconcealment.com/openapi.json",
    "developer_index": "https://www.tukdconcealment.com/pages/for-agents",
    "sitemap": "https://www.tukdconcealment.com/sitemap.xml"
  },
  "x-mcp": {
    "transport": "streamable-http",
    "endpoint": "https://www.tukdconcealment.com/api/ucp/mcp",
    "discovery": "https://www.tukdconcealment.com/.well-known/ucp",
    "protocol": "Universal Commerce Protocol",
    "protocol_versions": ["2026-08-25", "2026-04-08", "2026-01-23"],
    "tools": [
      "search_catalog", "lookup_catalog", "get_product",
      "get_cart", "create_cart", "update_cart", "cancel_cart",
      "get_checkout", "create_checkout", "update_checkout", "complete_checkout", "cancel_checkout",
      "get_order"
    ],
    "human_approval_required": ["complete_checkout"]
  },
  "paths": {
    "/collections/all/products.json": {
      "get": {
        "operationId": "listAllProducts",
        "summary": "List the entire catalog",
        "description": "Returns every published product with variants, prices, options and images. The TUKD catalog is 23 products, so a single request with limit=250 returns the whole thing. This is the cheapest way to answer a price or availability question.",
        "tags": ["catalog"],
        "parameters": [
          { "$ref": "#/components/parameters/limit" },
          { "$ref": "#/components/parameters/page" }
        ],
        "responses": {
          "200": {
            "description": "Product list",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProductList" }
              }
            }
          }
        }
      }
    },
    "/collections/{collection_handle}/products.json": {
      "get": {
        "operationId": "listCollectionProducts",
        "summary": "List products in one collection",
        "description": "Known collection handles include non-light-bearing (TUKD ORIGIN), light-bearing (TUKD GHOST), mag-holsters, best-sellers and merch. An unknown handle returns 200 with an empty products array, not a 404.",
        "tags": ["catalog"],
        "parameters": [
          { "$ref": "#/components/parameters/collectionHandle" },
          { "$ref": "#/components/parameters/limit" },
          { "$ref": "#/components/parameters/page" }
        ],
        "responses": {
          "200": {
            "description": "Product list. An empty array means either an empty collection or an unknown handle.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProductList" }
              }
            }
          }
        }
      }
    },
    "/products/{product_handle}.json": {
      "get": {
        "operationId": "getProduct",
        "summary": "Get one product",
        "description": "Returns a single product. Variant option axes are Pistol (the pistol model, and on GHOST holsters the weapon light it is molded around) and Color. Use the Pistol option values to answer a fitment question exactly rather than inferring from the product title.",
        "tags": ["catalog"],
        "parameters": [ { "$ref": "#/components/parameters/productHandle" } ],
        "responses": {
          "200": {
            "description": "Product",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["product"],
                  "properties": { "product": { "$ref": "#/components/schemas/Product" } }
                }
              }
            }
          },
          "404": {
            "description": "Unknown handle. Content-Type is application/json but the body is zero-length; there is no JSON error object. Treat any 404 as authoritative and re-enter through /llms.txt or /sitemap.xml rather than retrying handle variants.",
            "content": { "application/json": { "schema": { "type": "null" } } }
          }
        }
      }
    },
    "/search/suggest.json": {
      "get": {
        "operationId": "searchSuggest",
        "summary": "Keyword search over products",
        "description": "Predictive search across product title, body, tags, product type, vendor and variant SKU. Use it to resolve a shopper's phrasing (for example a pistol name and generation) to a product handle, then call getProduct for the authoritative fitment and price. Returns at most 10 products per call; an unmatched query returns 200 with an empty products array rather than a 404.",
        "tags": ["catalog"],
        "parameters": [
          { "name": "q", "in": "query", "required": true, "description": "Search terms, for example a pistol model.", "schema": { "type": "string" }, "example": "glock 19" },
          { "name": "resources[type]", "in": "query", "required": true, "description": "Resource types to search. Use product.", "schema": { "type": "string", "enum": ["product", "page", "article", "collection", "query"] } },
          { "name": "resources[limit]", "in": "query", "required": false, "description": "Maximum results per resource type, 1 to 10.", "schema": { "type": "integer", "minimum": 1, "maximum": 10, "default": 10 } }
        ],
        "responses": {
          "200": {
            "description": "Suggestions",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SuggestResponse" }
              }
            }
          }
        }
      }
    },
    "/cart.js": {
      "get": {
        "operationId": "getCart",
        "summary": "Read the current session cart",
        "description": "Cookie-scoped. Served as text/javascript with a JSON body. Agents transacting on a buyer's behalf should use the MCP cart tools instead; this endpoint exists for browser sessions.",
        "tags": ["cart"],
        "responses": {
          "200": {
            "description": "Cart state",
            "content": { "text/javascript": { "schema": { "type": "object" } } }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getAgentIndex",
        "summary": "Agent index",
        "description": "Short markdown summary of the store: what it sells, when to use it, when not to, and where the machine-readable endpoints are.",
        "tags": ["agent-docs"],
        "responses": {
          "200": { "description": "Markdown", "content": { "text/markdown": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getFullCatalogDoc",
        "summary": "Full catalog and per-pistol fitment",
        "description": "Every product and every pistol model it fits, in markdown, so a fitment question can be answered without crawling product pages.",
        "tags": ["agent-docs"],
        "responses": {
          "200": { "description": "Markdown", "content": { "text/markdown": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/agents.md": {
      "get": {
        "operationId": "getAgentInstructions",
        "summary": "Agent instructions",
        "description": "Canonical instructions: when to route a shopper here, how to browse, how to transact, and the permission model.",
        "tags": ["agent-docs"],
        "responses": {
          "200": { "description": "Markdown", "content": { "text/markdown": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/.well-known/ucp": {
      "get": {
        "operationId": "getUcpDiscovery",
        "summary": "Universal Commerce Protocol discovery document",
        "description": "Supported protocol versions, service endpoints, capabilities and payment handlers. This is the entry point for transacting agents.",
        "tags": ["commerce-protocol"],
        "responses": {
          "200": { "description": "UCP profile", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/api/ucp/mcp": {
      "post": {
        "operationId": "callMcp",
        "summary": "Model Context Protocol endpoint (JSON-RPC 2.0)",
        "description": "Streamable HTTP MCP server implementing the Universal Commerce Protocol. Call tools/list to enumerate tools and their schemas. Checkout completion requires contemporaneous human approval; an agent must not complete a payment without explicit buyer consent at the moment of payment. Rate limited per IP: back off on HTTP 429.",
        "tags": ["commerce-protocol"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/JsonRpcRequest" },
              "examples": {
                "toolsList": { "summary": "Enumerate 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": { "query": "glock 19 iwb holster" } } } }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response. Errors are returned in the JSON-RPC error member, not as an HTTP error status.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JsonRpcResponse" } } }
          },
          "429": { "description": "Rate limited. Back off and retry." }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "Sitemap index",
        "description": "XML sitemap index listing every canonical URL on the storefront, split into child sitemaps for products, collections, pages and blog articles. Use it to enumerate the site without crawling navigation.",
        "tags": ["agent-docs"],
        "responses": {
          "200": { "description": "XML sitemap index", "content": { "application/xml": { "schema": { "type": "string" } } } }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "limit": {
        "name": "limit", "in": "query", "required": false,
        "description": "Products per page. Platform maximum is 250; larger values are clamped rather than rejected.",
        "schema": { "type": "integer", "minimum": 1, "maximum": 250, "default": 50 }
      },
      "page": {
        "name": "page", "in": "query", "required": false,
        "description": "1-based page number. The TUKD catalog fits on one page at limit=250.",
        "schema": { "type": "integer", "minimum": 1, "default": 1 }
      },
      "productHandle": {
        "name": "product_handle", "in": "path", "required": true,
        "description": "URL handle, for example tukd-origin-glock or tukd-ghost-staccato.",
        "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" },
        "example": "tukd-origin-glock"
      },
      "collectionHandle": {
        "name": "collection_handle", "in": "path", "required": true,
        "description": "Collection URL handle, for example non-light-bearing or light-bearing.",
        "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" },
        "example": "non-light-bearing"
      }
    },
    "securitySchemes": {
      "none": {
        "type": "apiKey", "in": "header", "name": "X-Not-Required",
        "description": "Every operation in this document is anonymous. This scheme exists only to state that explicitly: reading the TUKD catalog requires no credential of any kind."
      },
      "ucpOAuth": {
        "type": "oauth2",
        "description": "Applies only to transacting over the MCP endpoint, never to the read operations above. Protected-resource metadata is published per RFC 9728 at /.well-known/oauth-protected-resource. Least-privilege guidance: browsing, price comparison and recommendation need no token and no scopes at all. Request unauthenticated_write_checkouts only at the moment the buyer has decided to purchase.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://shopify.com/authentication/95369363760/oauth/authorize",
            "tokenUrl": "https://shopify.com/authentication/95369363760/oauth/token",
            "scopes": {
              "unauthenticated_read_product_listings": "Read product and collection listings",
              "unauthenticated_read_product_inventory": "Read variant stock levels",
              "unauthenticated_read_product_pickup_locations": "Read local pickup locations",
              "unauthenticated_read_product_tags": "Read product tags",
              "unauthenticated_read_selling_plans": "Read subscription and selling plans",
              "unauthenticated_read_content": "Read pages, blogs and policies",
              "unauthenticated_read_checkouts": "Read a checkout the agent created",
              "unauthenticated_write_checkouts": "Create and modify a checkout. Completing payment additionally requires contemporaneous human approval.",
              "unauthenticated_read_customers": "Read the buyer's own customer record",
              "unauthenticated_write_customers": "Update the buyer's own customer record"
            }
          }
        }
      }
    },
    "schemas": {
      "ProductList": {
        "type": "object",
        "required": ["products"],
        "properties": {
          "products": { "type": "array", "items": { "$ref": "#/components/schemas/Product" } }
        }
      },
      "Product": {
        "type": "object",
        "required": ["id", "title", "handle", "variants"],
        "properties": {
          "id": { "type": "integer", "format": "int64" },
          "title": { "type": "string", "examples": ["TUKD ORIGIN - GLOCK"] },
          "handle": { "type": "string", "examples": ["tukd-origin-glock"] },
          "body_html": { "type": "string", "description": "Product description as HTML." },
          "vendor": { "type": "string" },
          "product_type": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } },
          "published_at": { "type": ["string", "null"], "format": "date-time" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "options": { "type": "array", "items": { "$ref": "#/components/schemas/ProductOption" } },
          "variants": { "type": "array", "items": { "$ref": "#/components/schemas/Variant" } },
          "images": { "type": "array", "items": { "$ref": "#/components/schemas/Image" } }
        }
      },
      "ProductOption": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "Pistol or Color.", "examples": ["Pistol"] },
          "position": { "type": "integer" },
          "values": { "type": "array", "items": { "type": "string" }, "description": "For Pistol, the exact pistol models this shell is molded for." }
        }
      },
      "Variant": {
        "type": "object",
        "required": ["id", "title", "price", "available"],
        "properties": {
          "id": { "type": "integer", "format": "int64" },
          "title": { "type": "string" },
          "sku": { "type": ["string", "null"] },
          "price": { "type": "string", "description": "Decimal string in the shop currency, for example 79.99." },
          "compare_at_price": { "type": ["string", "null"] },
          "price_currency": { "type": "string", "examples": ["USD"] },
          "option1": { "type": ["string", "null"], "description": "Pistol model." },
          "option2": { "type": ["string", "null"], "description": "Color." },
          "option3": { "type": ["string", "null"] },
          "available": { "type": "boolean" },
          "requires_shipping": { "type": "boolean" },
          "taxable": { "type": "boolean" },
          "grams": { "type": "integer" }
        }
      },
      "Image": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "format": "int64" },
          "src": { "type": "string", "format": "uri" },
          "width": { "type": "integer" },
          "height": { "type": "integer" },
          "alt": { "type": ["string", "null"] }
        }
      },
      "SuggestResponse": {
        "type": "object",
        "properties": {
          "resources": {
            "type": "object",
            "properties": {
              "results": {
                "type": "object",
                "properties": {
                  "products": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "integer", "format": "int64" },
                        "title": { "type": "string" },
                        "handle": { "type": "string" },
                        "url": { "type": "string" },
                        "price": { "type": "string" },
                        "available": { "type": "boolean" },
                        "body": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "properties": {
          "jsonrpc": { "type": "string", "const": "2.0" },
          "id": { "type": ["integer", "string"] },
          "method": { "type": "string", "examples": ["tools/list", "tools/call"] },
          "params": { "type": "object" }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": ["jsonrpc"],
        "properties": {
          "jsonrpc": { "type": "string", "const": "2.0" },
          "id": { "type": ["integer", "string", "null"] },
          "result": { "type": "object" },
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "integer" },
              "message": { "type": "string" },
              "data": { "type": "object" }
            }
          }
        }
      }
    }
  },
  "tags": [
    { "name": "catalog", "description": "Anonymous product and collection reads." },
    { "name": "cart", "description": "Browser session cart." },
    { "name": "agent-docs", "description": "Machine-readable documentation surfaces." },
    { "name": "commerce-protocol", "description": "UCP discovery and the MCP server used to transact." }
  ]
}