openapi: 3.1.0
info:
  title: UKLSP — UK Local Services Protocol
  version: 0.1-draft
  description: >-
    Open protocol for agent-bookable UK local services. Slots are
    server-authoritative; bookings require a human principal; demo listings
    cannot be booked. Schemas: https://uklsp.org/schemas/v0.1/
  license: {name: MIT}
servers:
  - url: https://api.uklsp.org
paths:
  /v0/discover:
    get:
      operationId: discover
      summary: Ranked providers with quotes for a service in a postcode district
      parameters:
        - {name: service, in: query, required: true, schema: {type: string}, example: cp12_gas_safety}
        - {name: postcode_district, in: query, required: true, schema: {type: string}, example: LS6}
      responses:
        "200": {description: Ranked results with pricing, credentials, certification level and demo flag}
        "400": {description: BAD_QUERY}
  /v0/providers/{provider_id}:
    get:
      operationId: getProvider
      summary: Full Provider manifest
      parameters: [{name: provider_id, in: path, required: true, schema: {type: string}}]
      responses:
        "200":
          description: Provider
          content:
            application/json:
              schema: {$ref: "https://uklsp.org/schemas/v0.1/provider.schema.json"}
        "404": {description: UNKNOWN_PROVIDER}
  /v0/providers/{provider_id}/slots:
    get:
      operationId: getSlots
      summary: Open availability slots (booked and expired-hold slots never returned)
      parameters:
        - {name: provider_id, in: path, required: true, schema: {type: string}}
        - {name: service, in: query, required: false, schema: {type: string}}
      responses:
        "200": {description: "{slots: AvailabilitySlot[]}"}
  /v0/bookings:
    post:
      operationId: createBooking
      summary: BookingRequest in, BookingConfirmation out
      requestBody:
        required: true
        content:
          application/json:
            schema: {$ref: "https://uklsp.org/schemas/v0.1/booking.schema.json"}
      responses:
        "201": {description: booking_confirmation (idempotent by request_id)}
        "403": {description: DEMO_PROVIDER}
        "409": {description: SLOT_TAKEN or PRICE_MISMATCH}
        "422": {description: HUMAN_PRINCIPAL_REQUIRED, OUT_OF_COVERAGE, SERVICE_NOT_OFFERED, MISSING_FIELD}
