{
  "openapi": "3.1.0",
  "info": {
    "title": "Ambiance Artist public API",
    "version": "1.0.0",
    "summary": "Browse seasonal decor packages and service areas, and contact or place an order with Ambiance Artist (Park City, Utah).",
    "description": "The public JSON API behind https://ambianceartist.com. It exposes the read-only catalog (packages, add-ons, delivery areas, FAQs, gallery) and the customer-facing write endpoints (contact message, order, card checkout).\n\nAll other `/api/*` routes are administrative and require a signed session cookie; they are intentionally not described here.\n\nPrices are in US dollars. Order totals are always recomputed on the server from the catalog — prices sent by a client are ignored.\n\nHuman documentation: https://ambianceartist.com/docs. Guidance for AI agents: https://ambianceartist.com/llms.txt.",
    "contact": {
      "name": "Ambiance Artist",
      "email": "contact@ambianceartist.com",
      "url": "https://ambianceartist.com/contact"
    }
  },
  "servers": [
    {
      "url": "https://ambianceartist.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Catalog",
      "description": "Read-only storefront data. No authentication."
    },
    {
      "name": "Content",
      "description": "Site copy and gallery."
    },
    {
      "name": "Contact",
      "description": "Send a message to the business."
    },
    {
      "name": "Orders",
      "description": "Place an order or start a card checkout."
    }
  ],
  "paths": {
    "/api/packages": {
      "get": {
        "operationId": "listPackages",
        "summary": "List decor packages and add-ons",
        "description": "Returns every package that is currently published and inside its availability window, including add-ons (`is_addon: true`). Sold-out packages stay in the list with `availability` set accordingly and cannot be ordered. Prices are in US dollars.",
        "tags": [
          "Catalog"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The public catalog, ordered by `display_order`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Package"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/packages/search": {
      "get": {
        "operationId": "searchPackages",
        "summary": "Search packages by keyword",
        "description": "Case-insensitive keyword search over the title, card description and description of active packages. Returns at most 10 results.",
        "tags": [
          "Catalog"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search term, matched case-insensitively against package title and descriptions. Maximum 200 characters. An empty value returns an empty list.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "pumpkin"
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Matching packages (possibly empty).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "packages"
                  ],
                  "properties": {
                    "packages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PackageSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/search": {
      "get": {
        "operationId": "searchCatalog",
        "summary": "Search packages by keyword (alias)",
        "description": "Alias of `searchPackages`. Also accepts `query` as the parameter name. Returns at most 10 results.",
        "tags": [
          "Catalog"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search term, matched case-insensitively against package title and descriptions. Maximum 200 characters. An empty value returns an empty list.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "pumpkin"
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Matching packages (possibly empty).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "packages"
                  ],
                  "properties": {
                    "packages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PackageSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/areas": {
      "get": {
        "operationId": "listServiceAreas",
        "summary": "List delivery and service areas",
        "description": "The areas Ambiance Artist delivers and installs in, with the delivery fee for each. Use `id` as `delivery_area_id` when placing an order.",
        "tags": [
          "Catalog"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Service areas ordered by `display_order`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ServiceArea"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/options": {
      "get": {
        "operationId": "listFormOptions",
        "summary": "List order form options",
        "description": "The choices offered when ordering: installation weeks, removal options, styling options and custom questions, each with a price adjustment. Option `label` values (and choice labels) are what an order request refers to.",
        "tags": [
          "Catalog"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Order form options ordered by `display_order`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FormOption"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/color-palettes": {
      "get": {
        "operationId": "listColorPalettes",
        "summary": "List color palettes",
        "description": "Color palettes a customer can choose for a package. A palette with `scope: \"global\"` applies to every package; `selected_packages` palettes list their `package_ids`.",
        "tags": [
          "Catalog"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Color palettes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ColorPalette"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/faq": {
      "get": {
        "operationId": "listFaqs",
        "summary": "List frequently asked questions",
        "description": "Published FAQ entries, ordered by `display_order`.",
        "tags": [
          "Content"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "FAQ entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Faq"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/portfolio": {
      "get": {
        "operationId": "listPortfolio",
        "summary": "List gallery images",
        "description": "Photos of completed installations with a title and category.",
        "tags": [
          "Content"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Gallery images ordered by `display_order`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PortfolioImage"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/socials": {
      "get": {
        "operationId": "listSocialLinks",
        "summary": "List social media profiles",
        "description": "The business social media profile links (inactive ones have `is_active: false`).",
        "tags": [
          "Content"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Social links ordered by `display_order`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SocialLink"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/site-content": {
      "get": {
        "operationId": "getSiteContent",
        "summary": "Read editable site copy",
        "description": "The marketing copy shown on the website. With `page`, returns that page's sections as an object keyed by section key; without it, returns every section as a flat array.",
        "tags": [
          "Content"
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Restrict the response to one page.",
            "schema": {
              "type": "string",
              "enum": [
                "home",
                "about",
                "how_it_works",
                "contact",
                "gallery",
                "autumn",
                "christmas",
                "addons",
                "terms",
                "privacy",
                "global",
                "collections",
                "cart",
                "footer"
              ]
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sections for the requested page, or all sections.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/SiteContentSection"
                      }
                    },
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SiteContentSection"
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/recommendations": {
      "post": {
        "operationId": "getRecommendedAddons",
        "summary": "Get recommended add-ons for a cart",
        "description": "Given the package ids in a cart, returns the add-ons the business recommends alongside them. Read-only: nothing is written. POST is used only because the cart is the input.",
        "tags": [
          "Catalog"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "type": "array",
                    "maxItems": 50,
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "description": "Package ids in the cart.",
                    "default": []
                  }
                }
              },
              "example": {
                "ids": [
                  "b5204a91-eacc-41e5-9174-ebf122e5cffa"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recommended add-ons (possibly empty).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Package"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request body or query failed validation. `code` is `invalid_json` or `validation_failed`; for the latter `field` names the offending property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/contact": {
      "post": {
        "operationId": "submitContactMessage",
        "summary": "Send a message to the business",
        "description": "Sends an inquiry (custom design request, booking question, etc.) to the owners, who reply by email or phone. Limited to 5 requests per 1 hour per client IP. The server may require a bot-verification token (`turnstileToken`); an automated client that cannot supply one should send the person to https://ambianceartist.com/contact instead.",
        "tags": [
          "Contact"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactMessageRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The message was stored and the owners were notified.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "status"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "Unread"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request body or query failed validation. `code` is `invalid_json` or `validation_failed`; for the latter `field` names the offending property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Limited to 5 requests per 1 hour per client IP.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window, e.g. `5;w=3600` (5 requests per 3600 seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the window. Always 0 on a 429.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window frees a slot.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/orders": {
      "post": {
        "operationId": "createOrder",
        "summary": "Place an order",
        "description": "Creates an order (payment status `Unpaid`, order status `New`) from package ids, quantities and option labels. The server prices the order itself from the catalog, delivery area and options; any price in the request is ignored, and `expected_total` is only compared with the computed total as a safety check (409 `PRICE_CHANGED` if they differ). Limited to 8 requests per 1 hour per client IP.",
        "tags": [
          "Orders"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "The created order, including the server-computed `subtotal`, fees, `total_amount` and `order_status`.",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "The request body or query failed validation. `code` is `invalid_json` or `validation_failed`; for the latter `field` names the offending property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The computed total differs from `expected_total`. Re-confirm with the returned `total`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriceChanged"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Limited to 8 requests per 1 hour per client IP.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window, e.g. `5;w=3600` (5 requests per 3600 seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the window. Always 0 on a 429.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window frees a slot.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/checkout": {
      "post": {
        "operationId": "createCheckoutSession",
        "summary": "Start a card payment (Stripe embedded checkout)",
        "description": "Prices the cart server-side and creates a Stripe Checkout Session. The caller completes payment in the browser with the returned `clientSecret`; an agent cannot finish this step on its own and should hand the person the site URL instead. `terms_accepted` must be `true`. Limited to 8 requests per 1 hour per client IP.",
        "tags": [
          "Orders"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "clientSecret"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "Stripe Checkout Session id."
                    },
                    "clientSecret": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request body or query failed validation. `code` is `invalid_json` or `validation_failed`; for the latter `field` names the offending property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The computed total differs from `expected_total`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriceChanged"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Limited to 8 requests per 1 hour per client IP.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window, e.g. `5;w=3600` (5 requests per 3600 seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed in the window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the window. Always 0 on a 429.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window frees a slot.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server failure. `code` is a reference such as `ERR-1A2B3C4D`; retry later and quote it to support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Structured error returned by every public endpoint.",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable message."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable identifier, e.g. `validation_failed`, `invalid_json`, `unauthorized`, `not_found`, `rate_limited`. For unexpected failures, a reference like `ERR-1A2B3C4D`."
          },
          "hint": {
            "type": "string",
            "description": "What to do next."
          },
          "docs": {
            "type": "string",
            "format": "uri",
            "description": "Where the convention is documented."
          },
          "field": {
            "type": "string",
            "description": "For `validation_failed`: dotted path of the offending property."
          }
        }
      },
      "RateLimitError": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Error"
          },
          {
            "type": "object",
            "properties": {
              "retryAfter": {
                "type": "integer",
                "description": "Seconds to wait; same as the Retry-After header."
              }
            }
          }
        ]
      },
      "PriceChanged": {
        "type": "object",
        "required": [
          "error",
          "total"
        ],
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "PRICE_CHANGED"
            ]
          },
          "total": {
            "type": "number",
            "description": "The total the server would charge now."
          },
          "previousTotal": {
            "type": "number"
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "Package": {
        "type": "object",
        "description": "A decor package or add-on. Internal cost and draft fields are never included.",
        "required": [
          "id",
          "slug",
          "title",
          "price"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "URL slug: https://ambianceartist.com/collections/autumn/{slug}."
          },
          "title": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "description": "US dollars."
          },
          "badge": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "card_description": {
            "type": "string"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "image_url": {
            "type": "string",
            "format": "uri"
          },
          "gallery_images": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "display_order": {
            "type": "integer"
          },
          "is_featured": {
            "type": "boolean"
          },
          "is_addon": {
            "type": "boolean",
            "description": "Add-ons are ordered together with a main package."
          },
          "is_sold_out": {
            "type": "boolean"
          },
          "max_quantity": {
            "type": [
              "integer",
              "null"
            ]
          },
          "season": {
            "type": [
              "string",
              "null"
            ]
          },
          "availability": {
            "type": "object",
            "additionalProperties": true,
            "description": "Derived availability state."
          }
        },
        "additionalProperties": true
      },
      "PackageSummary": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "title",
          "price"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Same as `title`."
          },
          "price": {
            "type": "number",
            "description": "US dollars."
          },
          "badge": {
            "type": "string"
          },
          "card_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": "string"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "image_url": {
            "type": "string",
            "format": "uri"
          },
          "is_active": {
            "type": "boolean"
          },
          "is_addon": {
            "type": "boolean"
          },
          "is_featured": {
            "type": "boolean"
          }
        }
      },
      "ServiceArea": {
        "type": "object",
        "required": [
          "id",
          "name",
          "fee"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "examples": [
              "Park City"
            ]
          },
          "fee": {
            "type": "number",
            "description": "Delivery fee in US dollars (0 = free)."
          },
          "description": {
            "type": "string",
            "examples": [
              "Free Delivery"
            ]
          },
          "theme": {
            "type": "string"
          },
          "display_order": {
            "type": "integer"
          },
          "latitude": {
            "type": [
              "number",
              "null"
            ]
          },
          "longitude": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "FormOptionChoice": {
        "type": "object",
        "required": [
          "label",
          "price_adjustment"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string",
            "description": "The value to send in an order request."
          },
          "price_adjustment": {
            "type": "number",
            "description": "US dollars added to the order when chosen."
          },
          "start_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "end_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "cutoff_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "active": {
            "type": "boolean"
          },
          "blackout": {
            "type": "boolean"
          },
          "blackout_reason": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FormOption": {
        "type": "object",
        "required": [
          "id",
          "type",
          "label",
          "choices"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "week",
              "removal",
              "custom_question",
              "styling"
            ]
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "input_type": {
            "type": "string",
            "enum": [
              "select",
              "radio",
              "checkbox",
              "text"
            ]
          },
          "is_required": {
            "type": "boolean"
          },
          "choices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FormOptionChoice"
            }
          },
          "package_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Packages this option applies to; empty or null means all."
          },
          "display_order": {
            "type": "integer"
          }
        }
      },
      "ColorPalette": {
        "type": "object",
        "required": [
          "id",
          "name",
          "colors"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "colors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "hex"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "hex": {
                  "type": "string",
                  "pattern": "^#[0-9A-Fa-f]{6}$"
                }
              }
            }
          },
          "scope": {
            "type": "string",
            "enum": [
              "global",
              "selected_packages"
            ]
          },
          "package_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "is_active": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          }
        }
      },
      "Faq": {
        "type": "object",
        "required": [
          "id",
          "question",
          "answer"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "question": {
            "type": "string"
          },
          "answer": {
            "type": "string"
          },
          "display_order": {
            "type": "integer"
          }
        }
      },
      "PortfolioImage": {
        "type": "object",
        "required": [
          "id",
          "image_url"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "image_url": {
            "type": "string",
            "format": "uri"
          },
          "display_order": {
            "type": "integer"
          },
          "show_on_home": {
            "type": "boolean"
          }
        }
      },
      "SocialLink": {
        "type": "object",
        "required": [
          "id",
          "platform",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "platform": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "display_order": {
            "type": "integer"
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "SiteContentSection": {
        "type": "object",
        "required": [
          "page",
          "section_key"
        ],
        "properties": {
          "page": {
            "type": "string"
          },
          "section_key": {
            "type": "string",
            "examples": [
              "home.hero"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "subtitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "body_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "extra_data": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ContactMessageRequest": {
        "type": "object",
        "required": [
          "email",
          "subject",
          "message"
        ],
        "description": "Provide `full_name` (or the legacy alias `name`).",
        "properties": {
          "full_name": {
            "type": "string",
            "maxLength": 200
          },
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "Legacy alias for `full_name`."
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 200
          },
          "phone": {
            "type": "string",
            "maxLength": 50
          },
          "subject": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "message": {
            "type": "string",
            "minLength": 1,
            "maxLength": 5000
          },
          "turnstileToken": {
            "type": "string",
            "maxLength": 4000,
            "description": "Cloudflare Turnstile token; required when bot verification is enabled."
          },
          "image_urls": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "type": "string",
              "maxLength": 500
            },
            "description": "URLs previously returned by `POST /api/contact/upload`."
          }
        },
        "example": {
          "full_name": "Jane Doe",
          "email": "jane@example.com",
          "subject": "Custom porch design",
          "message": "I would like a quote for a Christmas porch display in Heber City."
        }
      },
      "OrderItem": {
        "type": "object",
        "required": [
          "pkg"
        ],
        "description": "One cart line. Only the package id, quantity and option labels are trusted; everything priced is looked up server-side.",
        "properties": {
          "pkg": {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200,
                "description": "Package `id` from `listPackages`."
              }
            }
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          },
          "delivery_area_id": {
            "type": "string",
            "description": "A service area `id` from `listServiceAreas`. Required for a main package."
          },
          "delivery_week": {
            "type": "string",
            "description": "A `week` option choice label from `listFormOptions`. Required for a main package."
          },
          "removal_option": {
            "type": "string",
            "description": "A `removal` option choice label. Required for a main package."
          },
          "photo_permission": {
            "type": "string",
            "maxLength": 200
          },
          "care_acknowledged": {
            "type": "boolean"
          },
          "custom_options": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "string",
                  "maxLength": 200
                },
                {
                  "type": "array",
                  "maxItems": 20,
                  "items": {
                    "type": "string",
                    "maxLength": 200
                  }
                }
              ]
            },
            "description": "Answers to `custom_question` options, keyed by option label."
          },
          "color_palette_id": {
            "type": "string",
            "description": "A palette `id` from `listColorPalettes`."
          }
        }
      },
      "OrderRequest": {
        "type": "object",
        "required": [
          "items",
          "customer_first_name",
          "customer_last_name",
          "customer_email",
          "customer_phone",
          "customer_street",
          "customer_city",
          "customer_state",
          "customer_zip"
        ],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/OrderItem"
            }
          },
          "customer_first_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "customer_last_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "customer_company": {
            "type": "string",
            "maxLength": 200
          },
          "customer_email": {
            "type": "string",
            "format": "email",
            "maxLength": 200
          },
          "customer_phone": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50
          },
          "customer_street": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "customer_apartment": {
            "type": "string",
            "maxLength": 200
          },
          "customer_city": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "customer_state": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "customer_zip": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50
          },
          "customer_notes": {
            "type": "string",
            "maxLength": 2000
          },
          "expected_total": {
            "type": "number",
            "description": "Optional safety check against the server-computed total; never used as the price."
          }
        }
      },
      "CheckoutRequest": {
        "type": "object",
        "required": [
          "items",
          "customerDetails",
          "terms_accepted"
        ],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/OrderItem"
            }
          },
          "customerDetails": {
            "type": "object",
            "required": [
              "email"
            ],
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 200
              },
              "email": {
                "type": "string",
                "format": "email",
                "maxLength": 200
              },
              "phone": {
                "type": "string",
                "maxLength": 50
              },
              "address": {
                "type": "string",
                "maxLength": 500
              }
            }
          },
          "expected_total": {
            "type": "number"
          },
          "terms_accepted": {
            "type": "boolean",
            "const": true,
            "description": "Must be `true`: the customer accepted the Terms & Conditions and Privacy Policy."
          },
          "checkout_attempt_key": {
            "type": "string",
            "maxLength": 200,
            "description": "Stable id reused when retrying the same cart so it does not create a duplicate order."
          }
        }
      }
    }
  }
}