openapi: 3.0.3
info:
  title: Katalis UK Business Intelligence APIs
  version: 1.3.1
  description: >
    AI-summarised, honestly-scored intelligence over UK open data. Company enrichment,
    Business Score, company search, industry classification, accessibility audits, and
    document intelligence for Modern Slavery statements, Ofsted reports, CQC reports and
    charity annual reports. Get a free API key at https://meetkatalis.com/apis and
    authenticate with the `x-api-key` header. Rate limits: monthly credit quota per plan
    plus a burst ceiling of 60 requests/minute per key (429 with no credit used).
    Contains public sector information licensed under the Open Government Licence v3.0.
  contact:
    name: Katalis
    url: https://meetkatalis.com/apis
    email: katalis@meetkatalis.com
  license:
    name: Open Government Licence v3.0
    url: https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/
servers:
  - url: https://meetkatalis.com
paths:
  /api/v1/enrich:
    get:
      operationId: enrichCompany
      summary: Enrich a UK business
      description: Returns a verified profile for a UK company name or domain.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: q
          in: query
          required: true
          description: Company name or domain (e.g. "Greggs" or "greggs.co.uk").
          schema: { type: string, maxLength: 200 }
        - name: location
          in: query
          required: false
          description: Optional town/city to disambiguate.
          schema: { type: string, maxLength: 120 }
      responses:
        "200":
          description: Enriched profile
          content:
            application/json:
              schema: { $ref: "#/components/schemas/EnrichResponse" }
        "400": { description: "Missing or invalid q" }
        "401": { description: "Missing or wrong x-api-key" }
        "429": { description: "Monthly quota reached (upgrade) OR the 60 req/min burst brake (retry — burst 429s never consume credits)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/score:
    get:
      operationId: businessScore
      summary: Business Score for a UK business
      description: Enriches then grades the business outside-in, with a prioritised action plan.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, maxLength: 200 }
        - name: location
          in: query
          required: false
          schema: { type: string, maxLength: 120 }
      responses:
        "200":
          description: Score, per-category findings and action plan
        "400": { description: "Missing or invalid q" }
        "401": { description: "Missing or wrong x-api-key" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/batch:
    post:
      operationId: enrichBatch
      summary: Batch-enrich up to 25 UK businesses
      description: One call, one atomic credit consume (1 credit per item). Bad items return found:false in place.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [items]
              properties:
                items:
                  type: array
                  minItems: 1
                  maxItems: 25
                  items: { type: string }
                location: { type: string }
      responses:
        "200": { description: "Results array in input order, with creditsUsed" }
        "400": { description: "Missing or invalid items array" }
        "401": { description: "Missing or wrong x-api-key" }
        "429": { description: "Not enough credits for the whole batch, or burst brake" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/assess:
    post:
      operationId: assessFit
      summary: Fit & approach assessment (premium, 25 credits)
      description: >
        A target business plus what YOU sell → fit score, the target's observable signals
        mapped to your offer, a factual approach angle and an editable opener draft.
        Grounded in the verified profile; never predicts receptiveness.
      security:
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [target, offer]
              properties:
                target: { type: string, description: Company name or domain }
                offer: { type: string, description: What you sell and who it's for }
                location: { type: string }
      responses:
        "200": { description: "fitScore, fitReasons, signalsForYou, approachAngle, openerDraft, watchOuts" }
        "400": { description: "Missing target or offer" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Target could not be confidently identified" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/company-search:
    get:
      operationId: searchCompanies
      summary: Search UK registered companies
      description: Companies House search, cleaned and confidence-ranked (company-level only, never officer personal data).
      security:
        - ApiKeyAuth: []
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, maxLength: 200 }
        - name: limit
          in: query
          required: false
          description: Max results (1-50, default 10).
          schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
      responses:
        "200": { description: "Ranked company matches with 0-1 match confidence" }
        "400": { description: "Missing or invalid q" }
        "401": { description: "Missing or wrong x-api-key" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/industry-classifier:
    get:
      operationId: classifyIndustry
      summary: Classify a business's industry
      description: Returns official SIC codes, a plain-English industry label, what they do and a confidence rating.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, maxLength: 200 }
      responses:
        "200": { description: "Industry, SIC codes, description, confidence" }
        "400": { description: "Missing or invalid q" }
        "401": { description: "Missing or wrong x-api-key" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/accessibility-audit:
    get:
      operationId: auditAccessibility
      summary: Accessibility audit of a web page
      description: >
        Deterministic WCAG-flavoured checks over the rendered page — missing alt text,
        unlabelled forms, blocked zoom, nameless buttons and more. Honest diagnosis:
        automated checks catch only a minority of WCAG issues and every response says so.
        Never a compliance certification.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: url
          in: query
          required: true
          description: The page to audit.
          schema: { type: string, maxLength: 500 }
      responses:
        "200": { description: "Score, findings (each tied to a WCAG criterion) and passed checks" }
        "400": { description: "Missing or invalid url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Page could not be fetched" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/modern-slavery:
    get:
      operationId: scoreModernSlaveryStatementByUrl
      summary: Score a Modern Slavery Act statement (by URL)
      description: GET variant — pass the statement's URL (HTML or PDF); we fetch and read it.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: url
          in: query
          required: true
          schema: { type: string, maxLength: 500 }
      responses:
        "200": { description: "Structured six-area scoring with sign-off compliance and gaps" }
        "400": { description: "Missing url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
    post:
      operationId: scoreModernSlaveryStatement
      summary: Score a Modern Slavery Act statement
      description: Turns a UK Modern Slavery Act s.54 statement into structured, quality-scored JSON.
      security:
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                text: { type: string, description: The statement text }
                url: { type: string, description: An HTML or PDF statement URL (alternative to text) }
      responses:
        "200": { description: "Structured six-area scoring with sign-off compliance and gaps" }
        "400": { description: "Missing text and url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/ofsted-report:
    get:
      operationId: structureOfstedReportByUrl
      summary: Structure an Ofsted report card (by URL)
      description: GET variant — pass the report's URL (HTML or PDF); we fetch and read it.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: url
          in: query
          required: true
          schema: { type: string, maxLength: 500 }
      responses:
        "200": { description: "Structured grades, summary and themes" }
        "400": { description: "Missing url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
    post:
      operationId: structureOfstedReport
      summary: Structure an Ofsted report card
      description: Feed in an Ofsted report and get graded areas, a plain-English summary, strengths and safeguarding status.
      security:
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                text: { type: string }
                url: { type: string }
      responses:
        "200": { description: "Structured grades, summary and themes" }
        "400": { description: "Missing text and url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/cqc-report:
    get:
      operationId: structureCqcReportByUrl
      summary: Structure a CQC inspection report (by URL)
      description: GET variant — pass the report's URL (HTML or PDF, including CQC's own site); we fetch and read it.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: url
          in: query
          required: true
          schema: { type: string, maxLength: 500 }
      responses:
        "200": { description: "Structured ratings, summary, concerns" }
        "400": { description: "Missing url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
    post:
      operationId: structureCqcReport
      summary: Structure a CQC inspection report
      description: Overall rating, the five key questions, strengths, concerns and enforcement — structured from the report text.
      security:
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                text: { type: string }
                url: { type: string }
      responses:
        "200": { description: "Structured ratings, summary, concerns" }
        "400": { description: "Missing text and url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/charity-report:
    get:
      operationId: structureCharityReportByUrl
      summary: Structure a charity trustees' report (by URL)
      description: GET variant — pass the report's URL (HTML or PDF); we fetch and read it.
      security:
        - ApiKeyAuth: []
      parameters:
        - name: url
          in: query
          required: true
          schema: { type: string, maxLength: 500 }
      responses:
        "200": { description: "Structured due-diligence read with transparency score" }
        "400": { description: "Missing url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
    post:
      operationId: structureCharityReport
      summary: Structure a charity trustees' report for due diligence
      description: Finances, governance signals, delivery, flags, transparency score and the gaps a funder would ask about.
      security:
        - ApiKeyAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                text: { type: string }
                url: { type: string }
      responses:
        "200": { description: "Structured due-diligence read with transparency score" }
        "400": { description: "Missing text and url" }
        "401": { description: "Missing or wrong x-api-key" }
        "422": { description: "Document could not be fetched or read" }
        "429": { description: "Monthly quota reached OR burst brake (60/min)" }
        "503": { description: "Temporarily unavailable — retry" }
  /api/v1/company-logo:
    get:
      operationId: companyLogo
      summary: Company logo lookup (free, no key)
      security: []
      description: >
        Returns a link to a company's own published logo asset for a domain, with a legal
        `notice` field (nominative/identification use only — trademarks remain their
        owners'). Keyless and free; IP rate-limited. The /api/v1/demo endpoint is likewise
        keyless (one enrichment per IP per day) and intentionally undocumented here.
      parameters:
        - name: domain
          in: query
          required: true
          description: The company's domain (e.g. greggs.co.uk).
          schema: { type: string, maxLength: 200 }
      responses:
        "200": { description: "Logo URL(s) + the legal notice field" }
        "400": { description: "Missing or invalid domain" }
        "429": { description: "IP rate limit — retry later" }
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
  schemas:
    Signal:
      type: object
      properties:
        code: { type: string }
        label: { type: string }
        kind: { type: string, enum: [opportunity, risk, info] }
    Accuracy:
      type: object
      properties:
        score: { type: integer, example: 92 }
        confidence: { type: string, enum: [high, medium, low] }
        breakdown:
          type: array
          items:
            type: object
            properties:
              label: { type: string }
              points: { type: number }
              max: { type: number }
    BusinessProfile:
      type: object
      properties:
        found: { type: boolean }
        name: { type: string }
        website: { type: string }
        companyNumber: { type: string }
        status: { type: string }
        sicCodes: { type: array, items: { type: string } }
        incorporationDate: { type: string }
        sizeSignal: { type: string }
        whatTheyDo: { type: string }
        services: { type: array, items: { type: string } }
        sector: { type: string }
        signals: { type: array, items: { $ref: "#/components/schemas/Signal" } }
        accuracy: { $ref: "#/components/schemas/Accuracy" }
        confidence: { type: string, enum: [high, medium, low] }
        sources: { type: array, items: { type: string } }
        attribution: { type: string }
    EnrichResponse:
      type: object
      properties:
        ms: { type: integer }
        profile: { $ref: "#/components/schemas/BusinessProfile" }
