openapi: 3.1.0
info:
  title: Roof Cost Data Roof Quote Checker
  version: 1.0.0
  description: Read-only U.S. roof replacement planning range and written-scope review. The request contains structured project facts, not original quote documents.
servers:
  - url: https://roofcostdata.com
paths:
  /api/connector/roof-quote-check/v1:
    post:
      operationId: checkRoofReplacementQuote
      summary: Check a structured roof replacement quote
      description: Send structured facts only. Do not send quote documents, free-form text, homeowner contact details, or payment information. Maximum request body is 8 KiB.
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QuoteReviewInput'
      responses:
        '200':
          description: Planning range and written-scope review
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuoteReviewResult'
        '400':
          description: Malformed JSON or invalid fields
        '401':
          description: Missing or invalid integration key
        '413':
          description: Request body exceeds 8 KiB
        '415':
          description: Content type is not application/json
        '503':
          description: Service integration key is not configured
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Server-to-server integration key arranged with Roof Cost Data for an approved integration.
  schemas:
    ScopeStatus:
      type: string
      enum: [included, excluded, unclear, not_found, not_reviewed]
      description: not_found means absent from the supplied material reviewed, not proven absent from every contractor document. Omitted keys default to not_reviewed.
    QuoteReviewInput:
      type: object
      additionalProperties: false
      properties:
        location:
          type: object
          additionalProperties: false
          properties:
            city: { type: string, minLength: 2, maxLength: 100 }
            state: { type: string, minLength: 2, maxLength: 50 }
        roofAreaSqFt: { type: number, minimum: 100, maximum: 30000 }
        roofAreaBasis:
          type: string
          enum: [roof_surface, home_floor_area, unknown]
        materialId: { type: string, minLength: 1, maxLength: 60 }
        quotedTotalUsd: { type: number, minimum: 100, maximum: 10000000 }
        needsTearOff:
          type: [boolean, 'null']
          description: Whether the modeled replacement includes removal of the existing roof; null if unknown.
        scope:
          type: object
          additionalProperties: false
          properties:
            measuredRoofArea: { $ref: '#/components/schemas/ScopeStatus' }
            materialSystem: { $ref: '#/components/schemas/ScopeStatus' }
            tearOffAndDisposal: { $ref: '#/components/schemas/ScopeStatus' }
            underlayment: { $ref: '#/components/schemas/ScopeStatus' }
            flashing: { $ref: '#/components/schemas/ScopeStatus' }
            ventilation: { $ref: '#/components/schemas/ScopeStatus' }
            deckingAllowance: { $ref: '#/components/schemas/ScopeStatus' }
            permitsAndInspection: { $ref: '#/components/schemas/ScopeStatus' }
            cleanup: { $ref: '#/components/schemas/ScopeStatus' }
            paymentSchedule: { $ref: '#/components/schemas/ScopeStatus' }
            workmanshipWarranty: { $ref: '#/components/schemas/ScopeStatus' }
            changeOrders: { $ref: '#/components/schemas/ScopeStatus' }
    QuoteReviewResult:
      type: object
      required: [modelUpdated, methodologyUrl, market, material, planningRangeUsd, pricePosition, priceExplanation, assumptions, scopeFindings, questionsForContractor, limitations]
      properties:
        modelUpdated: { type: string, format: date }
        methodologyUrl: { type: string, format: uri }
        cityPageUrl: { type: [string, 'null'], format: uri }
        market:
          type: object
          properties:
            basis: { type: string, enum: [city, national] }
            city: { type: string }
            state: { type: string }
        material:
          type: [object, 'null']
          properties:
            id: { type: string }
            name: { type: string }
        planningRangeUsd:
          type: [object, 'null']
          properties:
            min: { type: number }
            max: { type: number }
        pricePosition:
          type: string
          enum: [below, within, above, not_comparable]
        priceExplanation: { type: string }
        assumptions:
          type: array
          items: { type: string }
        scopeFindings:
          type: array
          items:
            type: object
            properties:
              key: { type: string }
              label: { type: string }
              status: { $ref: '#/components/schemas/ScopeStatus' }
              question: { type: [string, 'null'] }
        questionsForContractor:
          type: array
          items: { type: string }
        limitations: { type: string }
