openapi: 3.1.0
info:
  title: Mortgage Magic API
  version: 0.1.0
  x-status: draft, endpoints gated
  description: >-
    UK mortgage product, criteria, address and performance data, licensed to
    businesses by Mortgage Magic Limited, company number 16426513, England and
    Wales. Endpoints are gated; request access at
    https://mortgagemagic.ai/contact.
  termsOfService: https://mortgagemagic.ai/legal/terms
  contact:
    name: Mortgage Magic Limited
    url: https://mortgagemagic.ai/contact
servers:
  - url: https://api.mortgagemagic.ai/v1
security:
  - ApiKeyAuth: []
tags:
  - name: sourcing
    description: Mortgage Sourcing API
  - name: data
    description: Data API
  - name: addresses
    description: Address Data
  - name: intelligence
    description: Mortgage and Finance Intelligence
  - name: events
    description: Webhook subscriptions
paths:
  /products:
    get:
      tags: [sourcing]
      summary: Search mortgage products
      operationId: listProducts
      parameters:
        - name: ltv
          in: query
          schema: { type: number }
          description: Maximum loan to value, percent
        - name: term
          in: query
          schema: { type: integer }
          description: Term in months
        - name: type
          in: query
          schema:
            type: string
            enum: [residential, buy-to-let, second-charge, commercial]
      responses:
        "200":
          description: Matching products
          content:
            application/json:
              schema:
                type: object
                properties:
                  count: { type: integer }
                  as_of: { type: string, format: date-time }
                  products:
                    type: array
                    items: { $ref: "#/components/schemas/Product" }
  /products/{productId}:
    get:
      tags: [sourcing]
      summary: Retrieve a product by id
      operationId: getProduct
      parameters:
        - name: productId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: The product record
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Product" }
  /lenders:
    get:
      tags: [data]
      summary: List lenders
      operationId: listLenders
      responses:
        "200":
          description: Lender reference data
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/Lender" }
  /lenders/{lenderId}/criteria:
    get:
      tags: [data]
      summary: Retrieve criteria answers for a lender
      operationId: getLenderCriteria
      parameters:
        - name: lenderId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Criteria answers with source and version
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/CriteriaAnswer" }
  /criteria/search:
    post:
      tags: [data]
      summary: Search criteria across lenders
      operationId: searchCriteria
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query: { type: string }
                lender: { type: string }
      responses:
        "200":
          description: Matching criteria answers
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/CriteriaAnswer" }
  /addresses/lookup:
    get:
      tags: [addresses]
      summary: Look up and validate a UK address
      operationId: lookupAddress
      parameters:
        - name: query
          in: query
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Candidate addresses with provenance
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/Address" }
  /addresses/{uprn}:
    get:
      tags: [addresses]
      summary: Retrieve a property by UPRN
      operationId: getAddress
      parameters:
        - name: uprn
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: The property record with provenance
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Address" }
  /intelligence/benchmarks:
    get:
      tags: [intelligence]
      summary: Retrieve aggregated performance benchmarks
      operationId: getBenchmarks
      responses:
        "200":
          description: Aggregated, anonymised benchmark series
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/Benchmark" }
  /events/subscriptions:
    post:
      tags: [events]
      summary: Create a webhook subscription
      operationId: createSubscription
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url, events]
              properties:
                url: { type: string, format: uri }
                events:
                  type: array
                  items: { type: string }
      responses:
        "201":
          description: Subscription created
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Subscription" }
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
  schemas:
    Product:
      type: object
      properties:
        product_id: { type: string }
        lender: { type: string }
        rate: { type: number }
        apr: { type: number }
        fee: { type: number }
        max_ltv: { type: number }
        source_url: { type: string, format: uri }
        version: { type: integer }
    Lender:
      type: object
      properties:
        lender_id: { type: string }
        name: { type: string }
    CriteriaAnswer:
      type: object
      properties:
        lender_id: { type: string }
        topic: { type: string }
        answer: { type: string }
        source_url: { type: string, format: uri }
        version: { type: integer }
    Address:
      type: object
      properties:
        uprn: { type: string }
        line_1: { type: string }
        line_2: { type: string }
        post_town: { type: string }
        postcode: { type: string }
        provenance:
          type: object
          properties:
            source: { type: string }
            retrieved_at: { type: string, format: date-time }
    Benchmark:
      type: object
      properties:
        metric: { type: string }
        period: { type: string }
        value: { type: number }
        basis: { type: string }
    Subscription:
      type: object
      properties:
        subscription_id: { type: string }
        url: { type: string, format: uri }
        events:
          type: array
          items: { type: string }
