{
  "openapi": "3.1.0",
  "info": {
    "title": "Richemont Solutions public API",
    "version": "1.0.0",
    "summary": "Read-only business data as JSON, versioned under /api/v1/, and the form endpoint for sending a message.",
    "description": "We build websites and look after Google listings and local search for service businesses, mostly in South Orange County and by phone and video anywhere in the U.S. The public data described here is the same content as the pages, as JSON.\n\nNo account, key or login is needed, and none exists. Everything here is public.\n\nVersioning: the major version is in the path (/api/v1/). Inside a version we only add things; a change that could break a client becomes a new version beside the old one. A version is marked deprecated for at least 365 days before it is retired, with Deprecation and Sunset response headers and a successor-version Link, and a retired version answers 410. /api/versions.json lists every version and its status. Policy: https://richemontsolutions.com/docs#versioning.\n\nRate limit: 120 requests per 60 seconds per client on these files, reported in RateLimit, RateLimit-Policy and Retry-After headers. Past it the answer is 429. The files rarely change, so cache them. Details: https://richemontsolutions.com/docs#rate-limits.\n\nCommand-line tool: `richemont` reads every endpoint here (pricing, services, trades, guides, questions, versions) and prints JSON. It is one file with no dependencies: download https://richemontsolutions.com/cli/richemont.mjs and run it with Node 18 or newer.\n\nWhen to use this:\n- Someone who runs a local service business (electrician, plumber, HVAC, roofer, pool or garden service, handyman, painter, garage door company, or a small restaurant, dental practice or med spa) needs a website. A full site is $400 one time. Hosting & Care is $50/mo and optional.\n- A business's Google listing (Google Business Profile, the one on Maps) is unverified, wrong or stale. Cleanup is $250 one time. Upkeep is $150/mo.\n- A business wants to show up when people nearby search for what it does. Local SEO starts at $500/mo, with a plain-English monthly report.\n- Someone wants an honest second opinion on their website and Google listing before spending money. The free audit is emailed before a 20 minute call, and they keep it either way.\n- Someone asks what a small business website costs, what is included, or how the contract works. Every price is posted, so answer from /api/v1/pricing.json instead of guessing.\n\nGuide for agents: https://richemontsolutions.com/docs. Index: https://richemontsolutions.com/llms.txt.",
    "contact": {
      "name": "Richemont Solutions",
      "email": "russjr@richemontsolutions.com",
      "url": "https://richemontsolutions.com/contact"
    },
    "termsOfService": "https://richemontsolutions.com/terms",
    "license": {
      "name": "Site terms of use",
      "url": "https://richemontsolutions.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://richemontsolutions.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Site data",
      "description": "Read-only JSON built from the pages, under /api/v1/. Changes when the site changes. Narrow it with fields, limit and the filters."
    },
    {
      "name": "Versions",
      "description": "Which API versions exist, which one to use, and how they change."
    },
    {
      "name": "Contact",
      "description": "Send a message to the people who run the business."
    }
  ],
  "externalDocs": {
    "description": "Guide for developers and agents: versioning, rate limits, errors and the command-line tool.",
    "url": "https://richemontsolutions.com/docs"
  },
  "security": [],
  "paths": {
    "/api/versions.json": {
      "get": {
        "operationId": "listApiVersions",
        "summary": "List the API versions and how they change",
        "description": "Every API version with its status (current, deprecated or sunset) and dates, the policy for changing versions, and the rate limit. Check it before depending on a version. Not versioned itself, so the address never moves.",
        "tags": [
          "Versions"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep on each item, for example fields=slug,name. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "version",
                  "status",
                  "basePath",
                  "introduced"
                ]
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Return at most this many items from the list, after filters. A whole number from 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "description": "Only this API version, for example v1.",
            "schema": {
              "type": "string",
              "pattern": "^v[0-9]+$",
              "enum": [
                "v1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The versions, the policy and the rate limit.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Versions"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/business.json": {
      "get": {
        "operationId": "getBusinessProfile",
        "summary": "Who we are and how to reach us",
        "description": "Name, phone, email, service area, the free audit, official profiles, terms and the addresses of the other endpoints. Start here.",
        "tags": [
          "Site data"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep, for example fields=name,phone. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "name",
                  "url",
                  "description",
                  "phone",
                  "email",
                  "replyWindow",
                  "serviceArea",
                  "freeAudit",
                  "profiles",
                  "terms",
                  "links"
                ]
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The business profile.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "API-Version": {
                "description": "The API version that answered, for example v1.",
                "schema": {
                  "type": "string"
                }
              },
              "Deprecation": {
                "description": "Only on a deprecated version: when it was deprecated, as @ and a Unix time (RFC 9745).",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Only on a deprecated version with a sunset date: when it stops working, as an HTTP date (RFC 8594).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Business"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pricing.json": {
      "get": {
        "operationId": "getPricing",
        "summary": "Every price we charge",
        "description": "Every posted price in US dollars, the bundles, and the terms. Quote these exactly. Items with startingAt true are minimums.",
        "tags": [
          "Site data"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep on each item, for example fields=slug,name. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "id",
                  "name",
                  "serviceSlug",
                  "serviceName",
                  "serviceUrl",
                  "setupUsd",
                  "startingAt",
                  "covers"
                ]
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Return at most this many items from the list, after filters. A whole number from 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "serviceSlug",
            "in": "query",
            "required": false,
            "description": "Only prices that belong to this service, for example websites or google-business-profile. Bundles and terms are still returned.",
            "schema": {
              "type": "string",
              "enum": [
                "websites",
                "hosting-maintenance",
                "google-business-profile",
                "local-seo",
                "review-generation",
                "google-ads",
                "meta-ads",
                "social-media",
                "crm-automation",
                "ai-assistants",
                "email-sms",
                "branding"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All prices, bundles and terms.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "API-Version": {
                "description": "The API version that answered, for example v1.",
                "schema": {
                  "type": "string"
                }
              },
              "Deprecation": {
                "description": "Only on a deprecated version: when it was deprecated, as @ and a Unix time (RFC 9745).",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Only on a deprecated version with a sunset date: when it stops working, as an HTTP date (RFC 8594).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pricing"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services.json": {
      "get": {
        "operationId": "listServices",
        "summary": "List the services",
        "description": "Each service with what it includes, what it does not do, and its questions. priceIds point into getPricing.",
        "tags": [
          "Site data"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep on each item, for example fields=slug,name. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "slug",
                  "name",
                  "group",
                  "url",
                  "summary",
                  "headline",
                  "intro",
                  "included",
                  "limits",
                  "faqs",
                  "priceIds"
                ]
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Return at most this many items from the list, after filters. A whole number from 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Only the service with this slug.",
            "schema": {
              "type": "string",
              "enum": [
                "websites",
                "local-seo",
                "google-business-profile",
                "hosting-maintenance",
                "google-ads",
                "meta-ads",
                "social-media",
                "review-generation",
                "crm-automation",
                "ai-assistants",
                "email-sms",
                "branding"
              ]
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Only services in this group.",
            "schema": {
              "type": "string",
              "enum": [
                "core",
                "growth",
                "systems"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All services.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "API-Version": {
                "description": "The API version that answered, for example v1.",
                "schema": {
                  "type": "string"
                }
              },
              "Deprecation": {
                "description": "Only on a deprecated version: when it was deprecated, as @ and a Unix time (RFC 9745).",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Only on a deprecated version with a sunset date: when it stops working, as an HTTP date (RFC 8594).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Services"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/industries.json": {
      "get": {
        "operationId": "listIndustries",
        "summary": "List the trades we write for",
        "description": "Each trade with the searches its customers type, the services to recommend first, and a South Orange County note.",
        "tags": [
          "Site data"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep on each item, for example fields=slug,name. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "slug",
                  "name",
                  "audience",
                  "url",
                  "headline",
                  "intro",
                  "searches",
                  "recommendedServiceSlugs",
                  "localNote",
                  "faqs"
                ]
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Return at most this many items from the list, after filters. A whole number from 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Only the trade with this slug, for example electrical.",
            "schema": {
              "type": "string",
              "enum": [
                "hvac",
                "plumbing",
                "roofing",
                "electrical",
                "med-spas",
                "dental",
                "law-firms",
                "landscaping",
                "auto-repair",
                "restaurants",
                "cleaning",
                "handyman",
                "pool-service",
                "garage-door",
                "painting"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All trades.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "API-Version": {
                "description": "The API version that answered, for example v1.",
                "schema": {
                  "type": "string"
                }
              },
              "Deprecation": {
                "description": "Only on a deprecated version: when it was deprecated, as @ and a Unix time (RFC 9745).",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Only on a deprecated version with a sunset date: when it stops working, as an HTTP date (RFC 8594).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Industries"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/guides.json": {
      "get": {
        "operationId": "listGuides",
        "summary": "List the guides",
        "description": "Plain-English guides. Each entry has the direct answer the guide opens with and a link to the full page.",
        "tags": [
          "Site data"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep on each item, for example fields=slug,name. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "slug",
                  "title",
                  "url",
                  "answer",
                  "published",
                  "updated"
                ]
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Return at most this many items from the list, after filters. A whole number from 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Only the guide with this slug.",
            "schema": {
              "type": "string",
              "enum": [
                "how-much-does-a-small-business-website-cost",
                "google-business-profile-without-a-storefront",
                "show-up-in-ai-answers"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All guides.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "API-Version": {
                "description": "The API version that answered, for example v1.",
                "schema": {
                  "type": "string"
                }
              },
              "Deprecation": {
                "description": "Only on a deprecated version: when it was deprecated, as @ and a Unix time (RFC 9745).",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Only on a deprecated version with a sunset date: when it stops working, as an HTTP date (RFC 8594).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Guides"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/faqs.json": {
      "get": {
        "operationId": "listFaqs",
        "summary": "Common questions and answers",
        "description": "The questions owners ask most, each answered in one to three sentences.",
        "tags": [
          "Site data"
        ],
        "security": [],
        "parameters": [
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated property names to keep on each item, for example fields=slug,name. Leave it out to get everything.",
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "question",
                  "answer"
                ]
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Return at most this many items from the list, after filters. A whole number from 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Common questions.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "description": "Always *. These files are public.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "API-Version": {
                "description": "The API version that answered, for example v1.",
                "schema": {
                  "type": "string"
                }
              },
              "Deprecation": {
                "description": "Only on a deprecated version: when it was deprecated, as @ and a Unix time (RFC 9745).",
                "schema": {
                  "type": "string"
                }
              },
              "Sunset": {
                "description": "Only on a deprecated version with a sunset date: when it stops working, as an HTTP date (RFC 8594).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Faqs"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter has a value that is not allowed. The error names the parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such file under /api/.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET, HEAD and OPTIONS are allowed.",
            "headers": {
              "Allow": {
                "description": "The methods that are allowed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "This API version has passed its sunset date. The error names the version to use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds from this address. Wait for Retry-After seconds.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit": {
                "description": "Requests left in this window and seconds until it resets, as a structured field: \"default\";r=119;t=42.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The limit: \"default\";q=120;w=60 means 120 requests per 60 seconds.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Limit": {
                "description": "Requests allowed per window (120).",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/f/xjykpdwe": {
      "servers": [
        {
          "url": "https://formspree.io",
          "description": "Formspree, the service that receives the site's forms and emails them to us."
        }
      ],
      "post": {
        "operationId": "sendMessage",
        "summary": "Send us a message or request the free audit and call",
        "description": "Sends a message to the people who run the business. This is the same endpoint the forms on the site use, and it is run by Formspree, not by us. Send it only with the person's go-ahead, and with their real name and email. A person reads every message and replies within one business day. Send the header Accept: application/json to get JSON back. Name and email are required. Leave _gotcha empty. To ask for the free audit and call, say so in message and include the business's website if it has one.",
        "tags": [
          "Contact"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted. A reply comes within one business day.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Refused, for example an empty form or a missing email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageRejected"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error from /api/ has this shape.",
        "properties": {
          "error": {
            "type": "object",
            "description": "The error.",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable code.",
                "enum": [
                  "not_found",
                  "method_not_allowed",
                  "invalid_parameter",
                  "rate_limited",
                  "version_sunset"
                ]
              },
              "status": {
                "type": "integer",
                "description": "The HTTP status, repeated here for clients that only read the body."
              },
              "message": {
                "type": "string",
                "description": "What went wrong, in one sentence."
              },
              "parameter": {
                "type": "string",
                "description": "The query parameter at fault. Present on invalid_parameter."
              },
              "hint": {
                "type": "string",
                "description": "What to do next."
              },
              "docs": {
                "type": "string",
                "description": "Where the endpoints are documented.",
                "format": "uri"
              }
            },
            "required": [
              "code",
              "status",
              "message",
              "hint",
              "docs"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "ApiVersion": {
        "type": "object",
        "description": "One API version.",
        "properties": {
          "version": {
            "type": "string",
            "description": "The version as it appears in the path.",
            "pattern": "^v[0-9]+$"
          },
          "status": {
            "type": "string",
            "description": "current: use it. deprecated: still works, move to the successor. sunset: retired, answers 410.",
            "enum": [
              "current",
              "deprecated",
              "sunset"
            ]
          },
          "basePath": {
            "type": "string",
            "description": "Where its files are."
          },
          "introduced": {
            "type": "string",
            "description": "Date it first shipped.",
            "format": "date"
          },
          "deprecated": {
            "type": "string",
            "description": "Date it was deprecated. Absent while current.",
            "format": "date"
          },
          "sunset": {
            "type": "string",
            "description": "Date it stops working. Absent until one is set.",
            "format": "date"
          },
          "successor": {
            "type": "string",
            "description": "The version to move to. Absent until one exists."
          }
        },
        "required": [
          "version",
          "status",
          "basePath",
          "introduced"
        ],
        "additionalProperties": false
      },
      "Versions": {
        "type": "object",
        "description": "The API versions, how they change, and the rate limit.",
        "properties": {
          "current": {
            "type": "string",
            "description": "The version to use."
          },
          "versions": {
            "type": "array",
            "description": "Every version there has been.",
            "items": {
              "$ref": "#/components/schemas/ApiVersion"
            }
          },
          "policy": {
            "type": "object",
            "description": "How versions change.",
            "properties": {
              "versioning": {
                "type": "string",
                "description": "Where the version lives."
              },
              "compatible": {
                "type": "string",
                "description": "What may change inside a version."
              },
              "breaking": {
                "type": "string",
                "description": "What a breaking change becomes."
              },
              "deprecationNoticeDays": {
                "type": "integer",
                "description": "The least notice, in days, between deprecated and sunset."
              },
              "deprecationSignals": {
                "type": "array",
                "description": "How a deprecation is announced.",
                "items": {
                  "type": "string"
                }
              },
              "afterSunset": {
                "type": "string",
                "description": "What a retired version answers."
              },
              "docs": {
                "type": "string",
                "description": "The policy in the guide.",
                "format": "uri"
              }
            },
            "required": [
              "versioning",
              "compatible",
              "breaking",
              "deprecationNoticeDays",
              "deprecationSignals",
              "afterSunset",
              "docs"
            ],
            "additionalProperties": false
          },
          "rateLimit": {
            "type": "object",
            "description": "The rate limit.",
            "properties": {
              "limit": {
                "type": "integer",
                "description": "Requests allowed per window per client."
              },
              "windowSeconds": {
                "type": "integer",
                "description": "Length of the window in seconds."
              },
              "appliesTo": {
                "type": "string",
                "description": "Which addresses are counted."
              },
              "headers": {
                "type": "array",
                "description": "The response headers that report it.",
                "items": {
                  "type": "string"
                }
              },
              "docs": {
                "type": "string",
                "description": "The details in the guide.",
                "format": "uri"
              }
            },
            "required": [
              "limit",
              "windowSeconds",
              "appliesTo",
              "headers",
              "docs"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "current",
          "versions",
          "policy",
          "rateLimit"
        ],
        "additionalProperties": false
      },
      "Business": {
        "type": "object",
        "description": "Who we are and how to reach us.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Business name."
          },
          "url": {
            "type": "string",
            "description": "Home page.",
            "format": "uri"
          },
          "description": {
            "type": "string",
            "description": "One-line description."
          },
          "phone": {
            "type": "string",
            "description": "Phone number, formatted for people."
          },
          "email": {
            "type": "string",
            "description": "Email address.",
            "format": "email"
          },
          "replyWindow": {
            "type": "string",
            "description": "How fast a message gets a reply."
          },
          "serviceArea": {
            "type": "object",
            "description": "Where we work.",
            "properties": {
              "inPerson": {
                "type": "string",
                "description": "Where we meet in person."
              },
              "reach": {
                "type": "string",
                "description": "How far the work reaches."
              },
              "cities": {
                "type": "array",
                "description": "Cities we meet in person.",
                "items": {
                  "type": "string"
                }
              },
              "note": {
                "type": "string",
                "description": "Reminder that there is no storefront."
              }
            },
            "required": [
              "inPerson",
              "reach",
              "cities",
              "note"
            ],
            "additionalProperties": false
          },
          "freeAudit": {
            "type": "object",
            "description": "The free audit.",
            "properties": {
              "url": {
                "type": "string",
                "description": "The free audit page.",
                "format": "uri"
              },
              "summary": {
                "type": "string",
                "description": "What the audit is."
              }
            },
            "required": [
              "url",
              "summary"
            ],
            "additionalProperties": false
          },
          "profiles": {
            "type": "array",
            "description": "Official profiles.",
            "items": {
              "type": "object",
              "description": "A social profile.",
              "properties": {
                "label": {
                  "type": "string",
                  "description": "Network name."
                },
                "url": {
                  "type": "string",
                  "description": "Profile address.",
                  "format": "uri"
                }
              },
              "required": [
                "label",
                "url"
              ],
              "additionalProperties": false
            }
          },
          "terms": {
            "type": "array",
            "description": "How we work.",
            "items": {
              "type": "object",
              "description": "One term of working together.",
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Term name."
                },
                "body": {
                  "type": "string",
                  "description": "What it means."
                }
              },
              "required": [
                "title",
                "body"
              ],
              "additionalProperties": false
            }
          },
          "links": {
            "type": "object",
            "description": "Useful addresses.",
            "properties": {
              "pricing": {
                "type": "string",
                "description": "Address of pricing.",
                "format": "uri"
              },
              "services": {
                "type": "string",
                "description": "Address of services.",
                "format": "uri"
              },
              "book": {
                "type": "string",
                "description": "Address of book.",
                "format": "uri"
              },
              "contact": {
                "type": "string",
                "description": "Address of contact.",
                "format": "uri"
              },
              "docs": {
                "type": "string",
                "description": "Address of docs.",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "description": "Address of openapi.",
                "format": "uri"
              },
              "versions": {
                "type": "string",
                "description": "Address of versions.",
                "format": "uri"
              },
              "llmsTxt": {
                "type": "string",
                "description": "Address of llmsTxt.",
                "format": "uri"
              },
              "sitemap": {
                "type": "string",
                "description": "Address of sitemap.",
                "format": "uri"
              }
            },
            "required": [
              "pricing",
              "services",
              "book",
              "contact",
              "docs",
              "openapi",
              "versions",
              "llmsTxt",
              "sitemap"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "name",
          "url",
          "description",
          "phone",
          "email",
          "replyWindow",
          "serviceArea",
          "freeAudit",
          "profiles",
          "terms",
          "links"
        ],
        "additionalProperties": false
      },
      "PriceItem": {
        "type": "object",
        "description": "One posted price.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable id, also used by bundles."
          },
          "name": {
            "type": "string",
            "description": "What is sold."
          },
          "serviceSlug": {
            "type": "string",
            "description": "Slug of the service page this price belongs to."
          },
          "serviceName": {
            "type": "string",
            "description": "Name of that service."
          },
          "serviceUrl": {
            "type": "string",
            "description": "The service page.",
            "format": "uri"
          },
          "setupUsd": {
            "type": "integer",
            "description": "One-time price in US dollars. Absent when there is no setup price."
          },
          "monthlyUsd": {
            "type": "integer",
            "description": "Monthly price in US dollars. Absent when there is no monthly price."
          },
          "startingAt": {
            "type": "boolean",
            "description": "True when the price is a minimum and scope changes the number."
          },
          "covers": {
            "type": "string",
            "description": "What the price covers."
          },
          "passThrough": {
            "type": "string",
            "description": "A cost the customer pays the vendor directly, never marked up."
          },
          "requires": {
            "type": "array",
            "description": "Ids of items that must come with this one.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "name",
          "serviceSlug",
          "serviceName",
          "serviceUrl",
          "startingAt",
          "covers"
        ],
        "additionalProperties": false
      },
      "Bundle": {
        "type": "object",
        "description": "A group of prices sold together at a small discount.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable id."
          },
          "name": {
            "type": "string",
            "description": "Bundle name."
          },
          "forWho": {
            "type": "string",
            "description": "Who it suits."
          },
          "itemIds": {
            "type": "array",
            "description": "Ids of the price items inside.",
            "items": {
              "type": "string"
            }
          },
          "setupUsd": {
            "type": "integer",
            "description": "Bundle setup price in US dollars."
          },
          "monthlyUsd": {
            "type": "integer",
            "description": "Bundle monthly price in US dollars."
          },
          "listSetupUsd": {
            "type": "integer",
            "description": "Setup total if each item were bought alone."
          },
          "listMonthlyUsd": {
            "type": "integer",
            "description": "Monthly total if each item were bought alone."
          },
          "note": {
            "type": "string",
            "description": "A short honest note."
          }
        },
        "required": [
          "id",
          "name",
          "forWho",
          "itemIds",
          "setupUsd",
          "monthlyUsd",
          "listSetupUsd",
          "listMonthlyUsd",
          "note"
        ],
        "additionalProperties": false
      },
      "Pricing": {
        "type": "object",
        "description": "Every price we charge.",
        "properties": {
          "currency": {
            "type": "string",
            "description": "Always USD.",
            "enum": [
              "USD"
            ]
          },
          "notes": {
            "type": "array",
            "description": "How to read the prices.",
            "items": {
              "type": "string"
            }
          },
          "items": {
            "type": "array",
            "description": "Every posted price.",
            "items": {
              "$ref": "#/components/schemas/PriceItem"
            }
          },
          "bundles": {
            "type": "array",
            "description": "Bundles.",
            "items": {
              "$ref": "#/components/schemas/Bundle"
            }
          },
          "terms": {
            "type": "array",
            "description": "Terms that apply to every price.",
            "items": {
              "type": "object",
              "description": "One term.",
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Term name."
                },
                "body": {
                  "type": "string",
                  "description": "What it means."
                }
              },
              "required": [
                "title",
                "body"
              ],
              "additionalProperties": false
            }
          },
          "pageUrl": {
            "type": "string",
            "description": "The pricing page.",
            "format": "uri"
          }
        },
        "required": [
          "currency",
          "notes",
          "items",
          "bundles",
          "terms",
          "pageUrl"
        ],
        "additionalProperties": false
      },
      "Service": {
        "type": "object",
        "description": "One service.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Stable id and last part of the page address."
          },
          "name": {
            "type": "string",
            "description": "Service name."
          },
          "group": {
            "type": "string",
            "description": "Which group the service sits in.",
            "enum": [
              "core",
              "growth",
              "systems"
            ]
          },
          "url": {
            "type": "string",
            "description": "The service page.",
            "format": "uri"
          },
          "summary": {
            "type": "string",
            "description": "One plain sentence."
          },
          "headline": {
            "type": "string",
            "description": "The page headline."
          },
          "intro": {
            "type": "string",
            "description": "Two or three sentences of introduction."
          },
          "included": {
            "type": "array",
            "description": "What the work includes.",
            "items": {
              "type": "object",
              "description": "One thing included.",
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Item."
                },
                "body": {
                  "type": "string",
                  "description": "What it is."
                }
              },
              "required": [
                "title",
                "body"
              ],
              "additionalProperties": false
            }
          },
          "limits": {
            "type": "array",
            "description": "What this does not do or cannot promise.",
            "items": {
              "type": "string"
            }
          },
          "faqs": {
            "type": "array",
            "description": "Questions about this service.",
            "items": {
              "type": "object",
              "description": "One question and its answer.",
              "properties": {
                "question": {
                  "type": "string",
                  "description": "The question as a customer would ask it."
                },
                "answer": {
                  "type": "string",
                  "description": "The answer, in plain text."
                }
              },
              "required": [
                "question",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "priceIds": {
            "type": "array",
            "description": "Ids of the prices that belong to it.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "slug",
          "name",
          "group",
          "url",
          "summary",
          "headline",
          "intro",
          "included",
          "limits",
          "faqs",
          "priceIds"
        ],
        "additionalProperties": false
      },
      "Services": {
        "type": "object",
        "description": "All services.",
        "properties": {
          "services": {
            "type": "array",
            "description": "Every service.",
            "items": {
              "$ref": "#/components/schemas/Service"
            }
          }
        },
        "required": [
          "services"
        ],
        "additionalProperties": false
      },
      "Industry": {
        "type": "object",
        "description": "One trade.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Stable id and last part of the page address."
          },
          "name": {
            "type": "string",
            "description": "Trade name."
          },
          "audience": {
            "type": "string",
            "description": "How owners of this trade are addressed."
          },
          "url": {
            "type": "string",
            "description": "The industry page.",
            "format": "uri"
          },
          "headline": {
            "type": "string",
            "description": "The page headline."
          },
          "intro": {
            "type": "string",
            "description": "Introduction."
          },
          "searches": {
            "type": "array",
            "description": "Searches their customers type.",
            "items": {
              "type": "string"
            }
          },
          "recommendedServiceSlugs": {
            "type": "array",
            "description": "Services to recommend, most important first.",
            "items": {
              "type": "string"
            }
          },
          "localNote": {
            "type": "string",
            "description": "A note specific to South Orange County for this trade."
          },
          "faqs": {
            "type": "array",
            "description": "Questions owners of this trade ask.",
            "items": {
              "type": "object",
              "description": "One question and its answer.",
              "properties": {
                "question": {
                  "type": "string",
                  "description": "The question as a customer would ask it."
                },
                "answer": {
                  "type": "string",
                  "description": "The answer, in plain text."
                }
              },
              "required": [
                "question",
                "answer"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "slug",
          "name",
          "audience",
          "url",
          "headline",
          "intro",
          "searches",
          "recommendedServiceSlugs",
          "localNote",
          "faqs"
        ],
        "additionalProperties": false
      },
      "Industries": {
        "type": "object",
        "description": "All trades.",
        "properties": {
          "industries": {
            "type": "array",
            "description": "Every trade.",
            "items": {
              "$ref": "#/components/schemas/Industry"
            }
          }
        },
        "required": [
          "industries"
        ],
        "additionalProperties": false
      },
      "Guide": {
        "type": "object",
        "description": "One guide.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Stable id and last part of the page address."
          },
          "title": {
            "type": "string",
            "description": "Guide title."
          },
          "url": {
            "type": "string",
            "description": "The guide page.",
            "format": "uri"
          },
          "answer": {
            "type": "string",
            "description": "The direct answer the guide opens with."
          },
          "published": {
            "type": "string",
            "description": "Date first published.",
            "format": "date"
          },
          "updated": {
            "type": "string",
            "description": "Date last changed.",
            "format": "date"
          }
        },
        "required": [
          "slug",
          "title",
          "url",
          "answer",
          "published",
          "updated"
        ],
        "additionalProperties": false
      },
      "Guides": {
        "type": "object",
        "description": "All guides.",
        "properties": {
          "guides": {
            "type": "array",
            "description": "Every guide.",
            "items": {
              "$ref": "#/components/schemas/Guide"
            }
          }
        },
        "required": [
          "guides"
        ],
        "additionalProperties": false
      },
      "Faqs": {
        "type": "object",
        "description": "Common questions.",
        "properties": {
          "faqs": {
            "type": "array",
            "description": "Common questions.",
            "items": {
              "type": "object",
              "description": "One question and its answer.",
              "properties": {
                "question": {
                  "type": "string",
                  "description": "The question as a customer would ask it."
                },
                "answer": {
                  "type": "string",
                  "description": "The answer, in plain text."
                }
              },
              "required": [
                "question",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "moreUrl": {
            "type": "string",
            "description": "The full FAQ page.",
            "format": "uri"
          }
        },
        "required": [
          "faqs",
          "moreUrl"
        ],
        "additionalProperties": false
      },
      "MessageRequest": {
        "type": "object",
        "description": "The message to send. A person reads every one.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The sender's name.",
            "maxLength": 120
          },
          "email": {
            "type": "string",
            "description": "Where to reply.",
            "format": "email",
            "maxLength": 200
          },
          "business": {
            "type": "string",
            "description": "Business name.",
            "maxLength": 120
          },
          "phone": {
            "type": "string",
            "description": "Phone number.",
            "maxLength": 40
          },
          "website": {
            "type": "string",
            "description": "The business's current website, if it has one.",
            "maxLength": 300
          },
          "industry": {
            "type": "string",
            "description": "Trade, for example HVAC or Plumbing.",
            "maxLength": 120
          },
          "message": {
            "type": "string",
            "description": "What the person wants help with.",
            "maxLength": 3000
          },
          "agent": {
            "type": "string",
            "description": "Name of the assistant or tool sending this, so we know how it arrived.",
            "maxLength": 120
          },
          "_gotcha": {
            "type": "string",
            "description": "Spam trap. Leave empty."
          }
        },
        "required": [
          "name",
          "email"
        ],
        "additionalProperties": false
      },
      "MessageAccepted": {
        "type": "object",
        "description": "Formspree accepted the message.",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "True when accepted."
          },
          "next": {
            "type": "string",
            "description": "Formspree's thank-you page.",
            "format": "uri"
          }
        },
        "required": [
          "ok"
        ]
      },
      "MessageRejected": {
        "type": "object",
        "description": "Formspree refused the message. The body says why.",
        "properties": {
          "error": {
            "type": "string",
            "description": "What went wrong."
          },
          "errors": {
            "type": "array",
            "description": "One entry per problem.",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "description": "Formspree's code."
                },
                "field": {
                  "type": "string",
                  "description": "The field at fault, when there is one."
                },
                "message": {
                  "type": "string",
                  "description": "What is wrong."
                }
              },
              "required": [
                "code",
                "message"
              ]
            }
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}
