{
  "openapi": "3.1.0",
  "info": {
    "title": "Diana Rafael Storefront API",
    "version": "2026-10-29",
    "summary": "Public, read-mostly catalog and cart API of dianarafael.com (natural black diamond fine jewelry).",
    "description": "Diana Rafael runs on Shopify. These are the standard public Shopify storefront endpoints, served on dianarafael.com, documented so AI agents and developers can search the catalog, read products and prices, and build a cart that a person checks out. No API key is needed. Nothing here exposes customer or order data. Every operation in this file is called by an automated contract test every night; an operation that stops working is removed from this file. Human documentation: https://dianarafael.com/pages/developers",
    "contact": {
      "name": "Diana Rafael customer care (a real person)",
      "email": "customercare@dianarafael.com",
      "url": "https://dianarafael.com/pages/new-website-book-online-appointment"
    }
  },
  "externalDocs": {
    "description": "Developers and AI agents page",
    "url": "https://dianarafael.com/pages/developers"
  },
  "servers": [
    { "url": "https://dianarafael.com", "description": "Production store (prices in USD)" }
  ],
  "tags": [
    { "name": "catalog", "description": "Products, collections and search (read-only)" },
    { "name": "cart", "description": "Session cart. A cart is tied to the cookie of the client that created it" },
    { "name": "graphql", "description": "Shopify Storefront GraphQL API, tokenless public access" }
  ],
  "paths": {
    "/products.json": {
      "get": {
        "tags": ["catalog"],
        "operationId": "listProducts",
        "summary": "List published products",
        "description": "Returns published products with variants, prices (USD strings), images and options. Paginate with page and limit.",
        "parameters": [
          { "name": "limit", "in": "query", "description": "Products per page (1-250).", "schema": { "type": "integer", "minimum": 1, "maximum": 250, "default": 30 } },
          { "name": "page", "in": "query", "description": "Page number, starting at 1. An empty products array means the last page was passed.", "schema": { "type": "integer", "minimum": 1, "default": 1 } }
        ],
        "responses": {
          "200": { "description": "A page of products", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProductList" } } } }
        }
      }
    },
    "/collections/{handle}/products.json": {
      "get": {
        "tags": ["catalog"],
        "operationId": "listCollectionProducts",
        "summary": "List the products of one collection",
        "description": "Same shape as listProducts, limited to one collection, e.g. black-ice (natural black diamond jewelry) or remnant.",
        "parameters": [
          { "name": "handle", "in": "path", "required": true, "description": "Collection handle, e.g. black-ice, black-rings, remnant.", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 250, "default": 30 } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } }
        ],
        "responses": {
          "200": { "description": "A page of products", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProductList" } } } },
          "404": { "description": "No collection with this handle" }
        }
      }
    },
    "/products/{handle}.js": {
      "get": {
        "tags": ["catalog"],
        "operationId": "getProduct",
        "summary": "Get one product by handle",
        "description": "Full product with variants. Prices are integers in cents (USD). Use a variant id with addToCart.",
        "parameters": [
          { "name": "handle", "in": "path", "required": true, "description": "Product handle, the last part of /products/<handle>.", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "The product", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProductJs" } } } },
          "404": { "description": "No published product with this handle" }
        }
      }
    },
    "/search/suggest.json": {
      "get": {
        "tags": ["catalog"],
        "operationId": "searchProducts",
        "summary": "Search products by text",
        "description": "Predictive search over products, e.g. q=black oval engagement ring.",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "description": "Search text.", "schema": { "type": "string" } },
          { "name": "resources[type]", "in": "query", "description": "Resource types to return.", "schema": { "type": "string", "default": "product", "enum": ["product", "collection", "article", "page", "product,collection"] } },
          { "name": "resources[limit]", "in": "query", "description": "Results per type (1-10).", "schema": { "type": "integer", "minimum": 1, "maximum": 10, "default": 10 } }
        ],
        "responses": {
          "200": { "description": "Search results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchSuggest" } } } }
        }
      }
    },
    "/cart.js": {
      "get": {
        "tags": ["cart"],
        "operationId": "getCart",
        "summary": "Read the current cart",
        "description": "Returns the cart bound to the caller's cart cookie (an empty cart for a new client). Prices in cents (USD).",
        "responses": {
          "200": { "description": "The cart", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Cart" } } } }
        }
      }
    },
    "/cart/add.js": {
      "post": {
        "tags": ["cart"],
        "operationId": "addToCart",
        "summary": "Add variants to the cart",
        "description": "Adds one or more variants. Errors come back as JSON with status, message and description (for example 422 \"Cannot find variant\"). Adding to a cart never buys anything; a person completes checkout.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["items"],
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": ["id", "quantity"],
                      "properties": {
                        "id": { "type": "integer", "description": "Variant id (from getProduct or listProducts)." },
                        "quantity": { "type": "integer", "minimum": 1 }
                      }
                    }
                  }
                }
              },
              "example": { "items": [{ "id": 51471286173865, "quantity": 1 }] }
            }
          }
        },
        "responses": {
          "200": { "description": "The added line items", "content": { "application/json": { "schema": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/CartLine" } } } } } } },
          "422": { "description": "Variant not found or not available", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CartError" } } } }
        }
      }
    },
    "/cart/change.js": {
      "post": {
        "tags": ["cart"],
        "operationId": "changeCartLine",
        "summary": "Change the quantity of a cart line",
        "description": "Sets the quantity of one line, identified by its line key from getCart. Quantity 0 removes the line.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["id", "quantity"],
                "properties": {
                  "id": { "type": "string", "description": "Line item key from getCart (items[].key)." },
                  "quantity": { "type": "integer", "minimum": 0 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "The updated cart", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Cart" } } } },
          "400": { "description": "Line not in the cart", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CartError" } } } },
          "422": { "description": "Invalid change", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CartError" } } } }
        }
      }
    },
    "/api/2026-10/graphql.json": {
      "post": {
        "tags": ["graphql"],
        "operationId": "storefrontGraphql",
        "summary": "Shopify Storefront GraphQL API (version 2026-10, no token)",
        "description": "Tokenless public access to the Shopify Storefront API: products, collections, search, menus and carts (cartCreate returns a checkoutUrl that a person opens to pay). The schema is versioned by date in the path and is introspectable. Tokenless access is limited to public data and to a query cost of 1,000 per query; the cost of each query is returned in extensions.cost. Errors come back as JSON in errors[] with extensions.code.",
        "externalDocs": { "url": "https://shopify.dev/docs/api/storefront/2026-10" },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["query"],
                "properties": {
                  "query": { "type": "string", "description": "GraphQL query or mutation." },
                  "variables": { "type": "object", "additionalProperties": true }
                }
              },
              "example": { "query": "{ products(first: 3, query: \"black oval\") { edges { node { handle title priceRange { minVariantPrice { amount currencyCode } } } } } }" }
            }
          }
        },
        "responses": {
          "200": { "description": "GraphQL result (data and/or errors)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GraphqlResponse" } } } }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Variant": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string", "description": "Option combination, e.g. \"Yellow / 6\" (gold color / ring size)" },
          "sku": { "type": ["string", "null"] },
          "available": { "type": "boolean" },
          "price": { "type": ["string", "integer"], "description": "products.json: USD string (\"2800.00\"); .js endpoints: integer cents" },
          "option1": { "type": ["string", "null"] },
          "option2": { "type": ["string", "null"] },
          "option3": { "type": ["string", "null"] }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string" },
          "handle": { "type": "string" },
          "body_html": { "type": ["string", "null"] },
          "vendor": { "type": "string" },
          "product_type": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } },
          "variants": { "type": "array", "items": { "$ref": "#/components/schemas/Variant" } },
          "images": { "type": "array", "items": { "type": "object", "properties": { "src": { "type": "string" } } } },
          "options": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "values": { "type": "array", "items": { "type": "string" } } } } }
        }
      },
      "ProductList": {
        "type": "object",
        "required": ["products"],
        "properties": { "products": { "type": "array", "items": { "$ref": "#/components/schemas/Product" } } }
      },
      "ProductJs": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "title": { "type": "string" },
          "handle": { "type": "string" },
          "description": { "type": "string" },
          "available": { "type": "boolean" },
          "price_min": { "type": "integer", "description": "Cents (USD)" },
          "price_max": { "type": "integer", "description": "Cents (USD)" },
          "options": { "type": "array", "items": { "type": "object" } },
          "variants": { "type": "array", "items": { "$ref": "#/components/schemas/Variant" } },
          "url": { "type": "string" }
        }
      },
      "SearchSuggest": {
        "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" },
                        "price": { "type": "string" },
                        "available": { "type": "boolean" },
                        "image": { "type": ["string", "null"] }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CartLine": {
        "type": "object",
        "properties": {
          "key": { "type": "string" },
          "id": { "type": "integer", "description": "Variant id" },
          "quantity": { "type": "integer" },
          "title": { "type": "string" },
          "price": { "type": "integer", "description": "Cents (USD)" },
          "url": { "type": "string" }
        }
      },
      "Cart": {
        "type": "object",
        "properties": {
          "token": { "type": "string" },
          "item_count": { "type": "integer" },
          "total_price": { "type": "integer", "description": "Cents" },
          "currency": { "type": "string", "example": "USD" },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/CartLine" } }
        }
      },
      "CartError": {
        "type": "object",
        "required": ["status", "message"],
        "properties": {
          "status": { "type": ["integer", "string"], "example": 422 },
          "message": { "type": "string", "example": "Cart Error" },
          "description": { "type": "string", "example": "Cannot find variant" }
        }
      },
      "GraphqlResponse": {
        "type": "object",
        "properties": {
          "data": { "type": ["object", "null"] },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "message": { "type": "string" },
                "path": { "type": "array", "items": { "type": "string" } },
                "extensions": { "type": "object", "properties": { "code": { "type": "string" } } }
              }
            }
          },
          "extensions": { "type": "object", "properties": { "cost": { "type": "object" } } }
        }
      }
    }
  }
}
