openapi: "3.1.0"
info:
  title: "Besiktningsman.se public HTTP API"
  version: "1.0.0"
  summary: "Catalog, prices, markdown pages, quote estimates, and quote leads."
  description: "Besiktningsman.se (Besiktningsmannen i Stockholm AB) is a Swedish building-inspection company. These routes are the public HTTP surface for agents: company facts, published prices, page markdown, a quote estimate, and a quote lead (offert). There is no API key. There is no sandbox and no CLI. Do not treat this API as a contractor dispatch, legal advice, or a software product."
  contact:
    name: Besiktningsman.se
    url: "https://www.besiktningsman.se/docs"
    email: "info@besiktningsman.se"
servers:
  - url: "https://www.besiktningsman.se"
    description: Production
tags:
  - name: catalog
    description: "Company, services, and published prices."
  - name: content
    description: "Markdown copies of public pages."
  - name: quotes
    description: "Estimates and quote leads."
paths:
  "/api/knowledge":
    get:
      operationId: getKnowledgeCatalog
      tags:
        - catalog
      summary: "Company catalog, prices, and knowledge index"
      description: "JSON catalog of Besiktningsman.se: legal entity, cities, services, hub prices, and regulatory document index."
      responses:
        "200":
          description: "Catalog payload."
          content:
            "application/json":
              schema:
                type: object
                additionalProperties: true
    post:
      operationId: postKnowledgeCatalogRejected
      tags:
        - catalog
      summary: "Knowledge catalog is GET only"
      responses:
        "405":
          description: "JSON error with code, message, and a resolution hint."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ApiError"
  "/api/lead-form/submit":
    post:
      operationId: submitQuoteLead
      tags:
        - quotes
      summary: "Submit a quote request (offert)"
      description: "Creates a quote lead. Send JSON or multipart. Required: email, phone, address, besiktningEllerKundtjanst. Optional: name, description, attachments."
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/QuoteLead"
      responses:
        "200":
          description: "Lead accepted."
          content:
            "application/json":
              schema:
                type: object
                additionalProperties: true
        "400":
          description: "JSON error with code, message, and a resolution hint."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ApiError"
        "405":
          description: "JSON error with code, message, and a resolution hint."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ApiError"
    get:
      operationId: getQuoteLeadRejected
      tags:
        - quotes
      summary: "Quote leads are POST only"
      responses:
        "405":
          description: "JSON error with code, message, and a resolution hint."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ApiError"
  "/api/assistant/quote-estimate":
    post:
      operationId: getQuoteEstimate
      tags:
        - quotes
      summary: "Published price estimate for a named service"
      description: "Returns a displayable estimate when serviceIdentifier matches a published privat or BRF row. Not a binding offer."
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/QuoteEstimateRequest"
      responses:
        "200":
          description: "Estimate payload."
          content:
            "application/json":
              schema:
                type: object
                additionalProperties: true
        "400":
          description: "JSON error with code, message, and a resolution hint."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ApiError"
        "422":
          description: "JSON error with code, message, and a resolution hint."
          content:
            "application/json":
              schema:
                "$ref": "#/components/schemas/ApiError"
  "/api/markdown/{slug}":
    get:
      operationId: getPageMarkdown
      tags:
        - content
      summary: "Markdown for a public page"
      description: "Same body as GET on the HTML path with Accept: text/markdown. Empty slug is the homepage."
      parameters:
        - name: slug
          in: path
          required: true
          description: "Path without a leading slash, for example priser or about."
          schema:
            type: string
      responses:
        "200":
          description: "Markdown document."
          content:
            "text/markdown":
              schema:
                type: string
        "404":
          description: "Unknown path. Markdown recovery body."
          content:
            "text/markdown":
              schema:
                type: string
  "/priser.md":
    get:
      operationId: getPricesMarkdown
      tags:
        - content
      summary: "Full service price list as markdown"
      responses:
        "200":
          description: "Price catalog."
          content:
            "text/markdown":
              schema:
                type: string
  "/openapi.json":
    get:
      operationId: getOpenApiJson
      tags:
        - catalog
      summary: "This OpenAPI document as JSON"
      responses:
        "200":
          description: "OpenAPI 3.1 document."
          content:
            "application/json":
              schema:
                type: object
components:
  schemas:
    ApiError:
      type: object
      required:
        - ok
        - error
        - code
        - message
      properties:
        ok:
          type: boolean
          const: false
        code:
          type: string
          description: "Stable machine code (not_found, validation_error, method_not_allowed)."
        message:
          type: string
          description: "Human-readable error."
        hint:
          type: string
          description: "Where to look next (OpenAPI, docs, or a working endpoint)."
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
            message:
              type: string
            hint:
              type: string
    QuoteLead:
      type: object
      required:
        - email
        - phone
        - address
        - besiktningEllerKundtjanst
      properties:
        email:
          type: string
          format: email
        phone:
          type: string
        address:
          type: string
          description: "Property address in Sweden."
        besiktningEllerKundtjanst:
          type: string
          description: "Inspection type or customer-service topic."
        name:
          type: string
        description:
          type: string
    QuoteEstimateRequest:
      type: object
      required:
        - serviceIdentifier
      properties:
        serviceIdentifier:
          type: string
          description: "Service slug such as overlatelsebesiktning."
          examples:
            - overlatelsebesiktning
        segment:
          type: string
          enum:
            - privat
            - brf
        tableId:
          type: string
        details:
          type: string
