{
  "openapi": "3.1.0",
  "info": {
    "title": "City Seamless Agent API",
    "version": "0.3.0",
    "description": "Agent-readable API for City Seamless Rain Gutter service questions and structured rain gutter bid requests. Agents may share the typical public gutter range of $475 to $2,500 and average City Seamless job of about $780, but requests are accepted for human review and do not book installations or quote final exact prices."
  },
  "servers": [
    {
      "url": "https://cityseamless.com",
      "description": "Production target"
    }
  ],
  "paths": {
    "/api/bid-request": {
      "get": {
        "operationId": "describeBidRequestEndpoint",
        "summary": "Describe the City Seamless bid request endpoint",
        "responses": {
          "200": {
            "description": "Endpoint metadata"
          }
        }
      },
      "post": {
        "operationId": "createBidRequest",
        "summary": "Create a structured rain gutter estimate request",
        "description": "Collects contact and job context for City Seamless human review. This endpoint does not book an install date, quote a final exact price, or guarantee availability.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BidRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Bid request accepted for City Seamless review",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BidRequestResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid required request fields"
          },
          "403": {
            "description": "Verification failed"
          },
          "429": {
            "description": "Rate limited"
          },
          "503": {
            "description": "Lead storage is not configured"
          }
        }
      }
    },
    "/api/agent-answer": {
      "post": {
        "operationId": "answerCitySeamlessQuestion",
        "summary": "Ask a grounded City Seamless service question",
        "description": "Returns a conservative answer grounded in public City Seamless site facts and safe next actions.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["question"],
                "properties": {
                  "question": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Grounded answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentAnswer"
                }
              }
            }
          }
        }
      }
    },
    "/api/runtime-config": {
      "get": {
        "operationId": "getRuntimeConfig",
        "summary": "Return public runtime configuration for browser forms",
        "description": "Returns the public Cloudflare Turnstile site key when configured. Does not return secrets.",
        "responses": {
          "200": {
            "description": "Runtime browser configuration"
          }
        }
      }
    },
    "/api/lead-events": {
      "post": {
        "operationId": "recordLeadEvent",
        "summary": "Record a non-PII lead event",
        "description": "Stores non-private attribution events such as phone clicks, text clicks, and form submissions so City Seamless can reconcile Google Ads, Google Business Profile, and website outcomes. Do not send customer private information to this endpoint.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadEvent"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Lead event accepted"
          },
          "400": {
            "description": "Invalid event type"
          }
        }
      }
    },
    "/mcp": {
      "get": {
        "operationId": "describeCitySeamlessMcp",
        "summary": "Describe the City Seamless MCP endpoint",
        "responses": {
          "200": {
            "description": "MCP metadata"
          }
        }
      },
      "post": {
        "operationId": "citySeamlessMcp",
        "summary": "Prototype JSON-RPC MCP endpoint",
        "description": "Provides tool discovery and safe bid-request preparation for City Seamless agent actions.",
        "responses": {
          "200": {
            "description": "JSON-RPC response"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BidRequest": {
        "description": "Either a human website form submission or an agent-originated bid request. Human form submissions require name and address. Agent-originated submissions require name, phone, city, service, and all agent attestation fields.",
        "discriminator": {
          "propertyName": "submission_type",
          "mapping": {
            "human": "#/components/schemas/HumanBidRequest",
            "agent": "#/components/schemas/AgentBidRequest"
          }
        },
        "oneOf": [
          { "$ref": "#/components/schemas/HumanBidRequest" },
          { "$ref": "#/components/schemas/AgentBidRequest" }
        ]
      },
      "HumanBidRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/BidRequestBase" },
          {
            "type": "object",
            "required": ["submission_type", "name", "address"],
            "properties": {
              "submission_type": { "type": "string", "const": "human" }
            },
            "description": "Website form submission reviewed by City Seamless. Phone and email are helpful but optional."
          }
        ]
      },
      "AgentBidRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/BidRequestBase" },
          {
            "type": "object",
            "required": [
              "submission_type",
              "name",
              "phone",
              "city",
              "service",
              "agent_identity",
              "agent_represents_human",
              "agent_contact_permission",
              "agent_not_speculative"
            ],
            "properties": {
              "submission_type": { "type": "string", "const": "agent" }
            },
            "description": "Agent-originated submission for a real human customer who gave permission to share contact information."
          }
        ]
      },
      "BidRequestBase": {
        "type": "object",
        "properties": {
          "submission_type": {
            "type": "string",
            "enum": ["human", "agent"],
            "description": "Use human for website form submissions and agent for assistant/browser-agent submissions."
          },
          "name": { "type": "string", "description": "Customer full name" },
          "phone": { "type": "string", "description": "Customer phone number. Optional for human form submissions, required for agent-originated submissions." },
          "email": { "type": "string", "format": "email", "description": "Customer email address. Optional for human form submissions." },
          "address": { "type": "string", "description": "Project address. Required for human form submissions." },
          "city": {
            "type": "string",
            "description": "Project city or service area. Required for agent-originated submissions.",
            "examples": ["Las Vegas", "Henderson", "Mesquite", "Boulder City", "Summerlin"]
          },
          "state": { "type": "string", "default": "NV" },
          "service": {
            "type": "string",
            "description": "Requested rain gutter service. Required for agent-originated submissions.",
            "examples": ["Gutter Installation", "K-Style Rain Gutters", "Leaf Guards and Leaf Screens", "Straight Face Gutters", "Commercial Gutter Installation"]
          },
          "preferred_window": { "type": "string", "description": "Preferred timing such as ASAP, this week, mornings, or flexible" },
          "customer_type": { "type": "string", "description": "Residential, commercial, HOA/property manager, or not sure" },
          "photos_available": { "type": "string", "description": "Whether the customer can text roofline photos" },
          "notes": { "type": "string", "description": "Project context, overflow areas, color needs, HOA notes, drainage issues, or other useful details" },
          "source": { "type": "string", "description": "Page path or referring source" },
          "page_title": { "type": "string" },
          "gclid": { "type": "string" },
          "gbraid": { "type": "string" },
          "wbraid": { "type": "string" },
          "utm_source": { "type": "string" },
          "utm_medium": { "type": "string" },
          "utm_campaign": { "type": "string" },
          "utm_term": { "type": "string" },
          "utm_content": { "type": "string" },
          "landing_page": { "type": "string" },
          "referrer": { "type": "string" },
          "turnstile_token": {
            "type": "string",
            "description": "Cloudflare Turnstile token when submitting from the public browser forms."
          },
          "agent_identity": {
            "type": "string",
            "description": "Required for agent-originated submissions. Name of the assistant, browser agent, or platform submitting for the customer."
          },
          "agent_represents_human": {
            "type": "boolean",
            "description": "Required and true for agent-originated submissions. Confirms the request represents a real human customer."
          },
          "agent_contact_permission": {
            "type": "boolean",
            "description": "Required and true for agent-originated submissions. Confirms the customer allowed the agent to share contact information with City Seamless."
          },
          "agent_not_speculative": {
            "type": "boolean",
            "description": "Required and true for agent-originated submissions. Confirms this is not a speculative, synthetic, spam, training, or test lead."
          },
          "agent_context": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional structured context supplied by a browser or AI agent. If present, agent attestation fields are required."
          }
        }
      },
      "BidRequestResponse": {
        "type": "object",
        "properties": {
          "status": { "type": "string", "const": "accepted" },
          "request_id": { "type": "string" },
          "message": { "type": "string" },
          "next_step": { "type": "string" }
        }
      },
      "LeadEvent": {
        "type": "object",
        "required": ["event_type"],
        "properties": {
          "event_type": {
            "type": "string",
            "enum": ["phone_click", "text_click", "form_submission", "call_conversion", "manual_call", "gbp_click"]
          },
          "request_id": {
            "type": "string",
            "description": "City Seamless request ID when the event is tied to a stored bid request."
          },
          "source": { "type": "string", "description": "Page path or source label" },
          "page_title": { "type": "string" },
          "event_label": { "type": "string" },
          "gclid": { "type": "string" },
          "gbraid": { "type": "string" },
          "wbraid": { "type": "string" },
          "utm_source": { "type": "string" },
          "utm_medium": { "type": "string" },
          "utm_campaign": { "type": "string" },
          "utm_term": { "type": "string" },
          "utm_content": { "type": "string" },
          "landing_page": { "type": "string" },
          "referrer": { "type": "string" },
          "event_data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Small non-PII event metadata. Do not include customer name, phone, email, or address."
          }
        }
      },
      "AgentAnswer": {
        "type": "object",
        "properties": {
          "answer": { "type": "string" },
          "sources": {
            "type": "array",
            "items": { "type": "string" }
          },
          "safe_next_action": { "type": "string" }
        }
      }
    }
  }
}
