{
  "openapi": "3.1.0",
  "info": {
    "title": "Hugo Plumbing Public API",
    "version": "1.0.0",
    "description": "Read-only public business information for Hugo Plumbing (Houston, TX) plus the customer service-request action. No customer or private company data is exposed. Read endpoints are static JSON regenerated on every site deploy; each is also reachable without the .json extension (e.g. /api/business).",
    "contact": {
      "name": "Hugo Plumbing",
      "url": "https://hugoplumbingtx.com/contact"
    },
    "x-llms-txt": "https://hugoplumbingtx.com/llms.txt"
  },
  "servers": [
    {
      "url": "https://hugoplumbingtx.com"
    }
  ],
  "paths": {
    "/api/business.json": {
      "get": {
        "operationId": "getBusiness",
        "summary": "Business profile: name, phone, address, hours, license, rating, service-area summary, available actions.",
        "responses": {
          "200": {
            "description": "Business profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Business"
                }
              }
            }
          }
        }
      }
    },
    "/api/services.json": {
      "get": {
        "operationId": "listServices",
        "summary": "All plumbing services offered, with problems solved, FAQs, applicable offers, and featured areas.",
        "responses": {
          "200": {
            "description": "Service list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceList"
                }
              }
            }
          }
        }
      }
    },
    "/api/service-areas.json": {
      "get": {
        "operationId": "getServiceAreas",
        "summary": "Every ZIP code and community served, plus per-area landing pages. Use `all_zips_served` to check coverage for an address.",
        "responses": {
          "200": {
            "description": "Service areas",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceAreas"
                }
              }
            }
          }
        }
      }
    },
    "/api/offers.json": {
      "get": {
        "operationId": "listOffers",
        "summary": "Current promotions with stable IDs and the services they apply to.",
        "responses": {
          "200": {
            "description": "Offers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferList"
                }
              }
            }
          }
        }
      }
    },
    "/api/faqs.json": {
      "get": {
        "operationId": "listFaqs",
        "summary": "Company FAQs and per-service FAQs.",
        "responses": {
          "200": {
            "description": "FAQs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/availability": {
      "get": {
        "operationId": "getAvailability",
        "summary": "Open appointment windows for the next 1–14 days (America/Chicago). Public, rate-limited.",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 14,
              "default": 7
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "First day to check (YYYY-MM-DD); defaults to the next bookable day."
          },
          {
            "name": "service",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Service slug from /api/services.json (used to size the window)."
          }
        ],
        "responses": {
          "200": {
            "description": "Windows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Availability"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query"
          },
          "429": {
            "description": "Rate limited — retry later"
          }
        }
      }
    },
    "/api/agent/book": {
      "post": {
        "operationId": "bookAppointment",
        "summary": "Book a firm appointment in a window returned by getAvailability. Requires an agent API key.",
        "description": "Authenticated write action for approved agents/partners (Bearer key issued by Hugo Plumbing). Set confirmed:true only after the customer has agreed to the window. Without a key, use POST /api/request-service with preferred_window instead. Idempotent per client_request_id.",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BookingRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Booked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookingResult"
                }
              }
            }
          },
          "400": {
            "description": "Validation error (message names the field)"
          },
          "401": {
            "description": "Missing/invalid agent key — response body points to the open alternatives"
          },
          "409": {
            "description": "Window no longer available, or duplicate client_request_id with a different payload"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/request-service": {
      "post": {
        "operationId": "requestService",
        "summary": "Submit a plumbing service request on behalf of a real customer. A Hugo Plumbing dispatcher calls the customer back.",
        "description": "Write action. Only submit with the customer's explicit consent and real contact details. Requests are validated, spam-filtered, and logged; abusive use is blocked. Accepts JSON, multipart/form-data, or application/x-www-form-urlencoded.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/ServiceRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ServiceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Request could not be recorded — call the business instead",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": false
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "agentKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Agent API key issued by Hugo Plumbing. Request one via /contact."
      }
    },
    "schemas": {
      "Availability": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "timezone": {
            "type": "string",
            "example": "America/Chicago"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "days": {
            "type": "integer"
          },
          "windows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "start": {
                  "type": "string",
                  "format": "date-time"
                },
                "end": {
                  "type": "string",
                  "format": "date-time"
                },
                "label": {
                  "type": "string",
                  "example": "Tue Sep 15, 8:00 AM – 12:00 PM"
                }
              }
            }
          },
          "note": {
            "type": "string"
          }
        }
      },
      "BookingRequest": {
        "type": "object",
        "required": [
          "confirmed",
          "customer",
          "address",
          "problem",
          "window"
        ],
        "properties": {
          "confirmed": {
            "type": "boolean",
            "const": true,
            "description": "The customer agreed to this window."
          },
          "customer": {
            "type": "object",
            "required": [
              "name",
              "phone"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "phone": {
                "type": "string",
                "description": "10-digit US number"
              },
              "email": {
                "type": "string",
                "format": "email"
              }
            }
          },
          "address": {
            "type": "object",
            "required": [
              "street",
              "zip"
            ],
            "properties": {
              "street": {
                "type": "string"
              },
              "city": {
                "type": "string",
                "default": "Houston"
              },
              "state": {
                "type": "string",
                "default": "TX"
              },
              "zip": {
                "type": "string",
                "pattern": "^\\d{5}$",
                "description": "Must be in /api/service-areas.json all_zips_served"
              }
            }
          },
          "service": {
            "type": "string",
            "description": "Service slug or short name"
          },
          "problem": {
            "type": "string",
            "minLength": 5,
            "maxLength": 2000
          },
          "window": {
            "type": "object",
            "required": [
              "start",
              "end"
            ],
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "end": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "notes": {
            "type": "string",
            "maxLength": 1000
          },
          "source": {
            "type": "string",
            "maxLength": 120,
            "example": "chatgpt-agent"
          },
          "client_request_id": {
            "type": "string",
            "maxLength": 80,
            "description": "Idempotency key; repeat-safe"
          }
        }
      },
      "BookingResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "requested"
            ],
            "description": "scheduled = window confirmed in the schedule; requested = job created, office will confirm the time by phone"
          },
          "booking_id": {
            "type": "string"
          },
          "window": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string"
              },
              "end": {
                "type": "string"
              },
              "label": {
                "type": "string"
              }
            }
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ServiceRequest": {
        "type": "object",
        "required": [
          "name",
          "phone",
          "problem"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100,
            "description": "Customer's full name"
          },
          "phone": {
            "type": "string",
            "description": "10-digit US phone number (any formatting)",
            "example": "(713) 555-0100"
          },
          "problem": {
            "type": "string",
            "minLength": 5,
            "maxLength": 2000,
            "description": "Plain-language description of the plumbing issue"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "address": {
            "type": "string",
            "maxLength": 200,
            "description": "Service address, Houston area"
          },
          "lead_source": {
            "type": "string",
            "maxLength": 300,
            "description": "Optional attribution note, e.g. 'chatgpt-agent'"
          },
          "preferred_window": {
            "type": "string",
            "maxLength": 120,
            "description": "Optional preferred appointment time (free text or an ISO range from getAvailability); the dispatcher confirms by phone"
          }
        }
      },
      "Business": {
        "type": "object",
        "description": "See GET /api/business for the live shape; keys are snake_case and stable."
      },
      "ServiceList": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Service"
            }
          }
        }
      },
      "Service": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "service_type": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "markdown_url": {
            "type": "string",
            "format": "uri"
          },
          "summary": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "audience": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "residential",
                "commercial"
              ]
            }
          },
          "problems_solved": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "offers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "featured_in_areas": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "faqs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "q": {
                  "type": "string"
                },
                "a": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ServiceAreas": {
        "type": "object",
        "properties": {
          "summary": {
            "type": "string"
          },
          "houston_zips_served": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "surrounding_communities": {
            "type": "array"
          },
          "area_pages": {
            "type": "array"
          },
          "all_zips_served": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "OfferList": {
        "type": "object",
        "properties": {
          "terms": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "amount_usd": {
                  "type": "number"
                },
                "applies_to": {
                  "type": "array"
                }
              }
            }
          }
        }
      }
    }
  }
}