openapi: 3.1.0
info:
  title: Find a Flight Partner API
  version: 1.0.0
  summary: Partner API for award-flight search, refresh, alerts, webhooks, usage,
    and PayRewards-aware enrichment.
  license:
    name: Proprietary
    url: https://findaflight.com.au/legal
  description: |
    Partner API v1 production contract. Find a Flight sells software and data access only.
    It does not sell flights, tickets, travel payments, or booking fulfilment.
servers:
- url: https://api.findaflight.com.au/v1
  description: Production
- url: https://vaqvasz1b3.execute-api.ap-southeast-2.amazonaws.com/v1
  description: Direct API Gateway fallback
security:
- ApiKeyAuth: []
x-faf-release:
  production_base_url: https://api.findaflight.com.au/v1
  live_routes:
  - POST /search
  - POST /search/flexible
  - GET /searches/{search_id}
  - POST /refresh
  - GET /refresh/{refresh_id}
  - GET /availability/{availability_id}
  - GET /coverage
  - GET /programmes
  - GET /airlines
  - POST /alerts
  - GET /alerts
  - GET /alerts/{alert_id}
  - PATCH /alerts/{alert_id}
  - DELETE /alerts/{alert_id}
  - POST /webhooks/endpoints
  - GET /webhooks/endpoints
  - GET /webhooks/events
  - GET /usage
  - GET /entitlements
  contracted_routes: []
  note: All listed v1 routes are enabled for authenticated production partner traffic.
tags:
- name: Search
  description: Search and retrieve partner-facing availability results.
- name: Refresh
  description: Request and inspect live refresh jobs.
- name: Reference
  description: Read coverage, programme, and airline reference data.
- name: Alerts
  description: Create and manage saved availability alerts.
- name: Webhooks
  description: Register endpoints and inspect webhook event delivery.
- name: Account
  description: Read usage, quota, and entitlement state.
paths:
  "/search":
    post:
      tags:
      - Search
      operationId: createSearch
      summary: Search bounded award availability.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      - "$ref": "#/components/parameters/FaFRequestId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/SearchRequest"
            examples:
              payRewardsBusiness:
                value:
                  origin: MEL
                  destinations:
                  - SIN
                  - HND
                  departure_date: '2026-09-15'
                  return_date: '2026-09-28'
                  cabin_classes:
                  - business
                  passengers:
                    adults: 2
                  programmes:
                  - QFF
                  - VFF
                  - KF
                  max_points: 500000
                  nonstop_preferred: true
                  partner_context:
                    partner:
                      partner_tenant_id: payrewards-demo
                      partner_user_id_hash: sha256:example
                      campaign_id: prp-q3-travel
                    rewards:
                      balance_band: 250k_500k
                      preferred_transfer_partners:
                      - Qantas
                      - KrisFlyer
                    payments:
                      volume_band: 50k_250k_monthly
                      category_mix:
                      - ATO
                      - Suppliers
                    travel:
                      destination_regions:
                      - Asia
                    consent:
                      personalisation: true
                      marketing: false
                      data_sharing: true
                      profiling: true
      responses:
        '200':
          description: Search completed synchronously.
          headers:
            X-FaF-Request-Id:
              "$ref": "#/components/headers/FaFRequestId"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/RateLimitRemaining"
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/SearchResponse"
        '202':
          description: Search accepted as an async job.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/AsyncJob"
        '400':
          "$ref": "#/components/responses/BadRequest"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '409':
          "$ref": "#/components/responses/Conflict"
        '429':
          "$ref": "#/components/responses/RateLimited"
  "/search/flexible":
    post:
      tags:
      - Search
      operationId: createFlexibleSearch
      summary: Start a flexible date or multi-destination search job.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/FlexibleSearchRequest"
      responses:
        '202':
          description: Flexible search accepted.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/AsyncJob"
        '400':
          "$ref": "#/components/responses/BadRequest"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '429':
          "$ref": "#/components/responses/RateLimited"
  "/searches/{search_id}":
    get:
      tags:
      - Search
      operationId: getSearch
      summary: Get search job status and results.
      parameters:
      - "$ref": "#/components/parameters/SearchId"
      - "$ref": "#/components/parameters/Cursor"
      - "$ref": "#/components/parameters/Limit"
      responses:
        '200':
          description: Search status and any available results.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/SearchResponse"
        '404':
          "$ref": "#/components/responses/NotFound"
  "/refresh":
    post:
      tags:
      - Refresh
      operationId: createRefresh
      summary: Request live refresh for an itinerary, route, or search result.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/RefreshRequest"
      responses:
        '202':
          description: Refresh accepted.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/AsyncJob"
        '400':
          "$ref": "#/components/responses/BadRequest"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '429':
          "$ref": "#/components/responses/RateLimited"
  "/refresh/{refresh_id}":
    get:
      tags:
      - Refresh
      operationId: getRefresh
      summary: Get refresh job status.
      parameters:
      - "$ref": "#/components/parameters/RefreshId"
      responses:
        '200':
          description: Refresh status.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/RefreshStatus"
        '404':
          "$ref": "#/components/responses/NotFound"
  "/availability/{availability_id}":
    get:
      tags:
      - Search
      operationId: getAvailability
      summary: Get one availability result by id.
      parameters:
      - "$ref": "#/components/parameters/AvailabilityId"
      responses:
        '200':
          description: Availability result.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Availability"
        '404':
          "$ref": "#/components/responses/NotFound"
  "/coverage":
    get:
      tags:
      - Reference
      operationId: getCoverage
      summary: List supported coverage and capability caveats.
      parameters:
      - name: programme
        in: query
        schema:
          type: string
      - name: airline
        in: query
        schema:
          type: string
      responses:
        '200':
          description: Coverage response.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/CoverageItem"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/programmes":
    get:
      tags:
      - Reference
      operationId: listProgrammes
      summary: List loyalty programmes.
      responses:
        '200':
          description: Programme list.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Programme"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/airlines":
    get:
      tags:
      - Reference
      operationId: listAirlines
      summary: List airlines.
      responses:
        '200':
          description: Airline list.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Airline"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/alerts":
    post:
      tags:
      - Alerts
      operationId: createAlert
      summary: Create an award availability alert.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/AlertCreateRequest"
      responses:
        '201':
          description: Alert created.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Alert"
        '400':
          "$ref": "#/components/responses/BadRequest"
    get:
      tags:
      - Alerts
      operationId: listAlerts
      summary: List alerts for the authenticated partner client.
      parameters:
      - "$ref": "#/components/parameters/Cursor"
      - "$ref": "#/components/parameters/Limit"
      responses:
        '200':
          description: Alert list.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Alert"
                  pagination:
                    "$ref": "#/components/schemas/Pagination"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/alerts/{alert_id}":
    get:
      tags:
      - Alerts
      operationId: getAlert
      summary: Retrieve an alert.
      parameters:
      - "$ref": "#/components/parameters/AlertId"
      responses:
        '200':
          description: Alert detail.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Alert"
        '404':
          "$ref": "#/components/responses/NotFound"
    patch:
      tags:
      - Alerts
      operationId: updateAlert
      summary: Update an alert.
      parameters:
      - "$ref": "#/components/parameters/AlertId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/AlertUpdateRequest"
      responses:
        '200':
          description: Alert updated.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Alert"
        '404':
          "$ref": "#/components/responses/NotFound"
    delete:
      tags:
      - Alerts
      operationId: deleteAlert
      summary: Delete an alert.
      parameters:
      - "$ref": "#/components/parameters/AlertId"
      responses:
        '204':
          description: Alert deleted.
        '404':
          "$ref": "#/components/responses/NotFound"
  "/webhooks/endpoints":
    post:
      tags:
      - Webhooks
      operationId: createWebhookEndpoint
      summary: Register a webhook endpoint.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WebhookEndpointCreateRequest"
      responses:
        '201':
          description: Webhook endpoint created. The signing secret is returned only
            once.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WebhookEndpointCreateResponse"
        '400':
          "$ref": "#/components/responses/BadRequest"
    get:
      tags:
      - Webhooks
      operationId: listWebhookEndpoints
      summary: List webhook endpoints.
      responses:
        '200':
          description: Webhook endpoint list.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/WebhookEndpoint"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/webhooks/events":
    get:
      tags:
      - Webhooks
      operationId: listWebhookEvents
      summary: List webhook events and delivery status.
      parameters:
      - "$ref": "#/components/parameters/Cursor"
      - "$ref": "#/components/parameters/Limit"
      - name: type
        in: query
        schema:
          "$ref": "#/components/schemas/WebhookEventType"
      responses:
        '200':
          description: Webhook event list.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/WebhookEvent"
                  pagination:
                    "$ref": "#/components/schemas/Pagination"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/usage":
    get:
      tags:
      - Account
      operationId: getUsage
      summary: Get usage for the authenticated partner client.
      parameters:
      - name: period
        in: query
        schema:
          type: string
          enum:
          - current_month
          - previous_month
          - last_30_days
          default: current_month
      responses:
        '200':
          description: Usage summary.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/UsageSummary"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
  "/entitlements":
    get:
      tags:
      - Account
      operationId: getEntitlements
      summary: Get entitlements for the authenticated partner client.
      responses:
        '200':
          description: Entitlement summary.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Entitlements"
        '401':
          "$ref": "#/components/responses/Unauthorised"
        '403':
          "$ref": "#/components/responses/Forbidden"
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: 'Use `Authorization: Bearer <partner_api_key>`.'
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        minLength: 8
        maxLength: 128
      description: Stable key for safely retrying mutation requests.
    FaFRequestId:
      name: X-FaF-Request-Id
      in: header
      required: false
      schema:
        type: string
        maxLength: 128
      description: Optional partner-provided request id.
    SearchId:
      name: search_id
      in: path
      required: true
      schema:
        type: string
    RefreshId:
      name: refresh_id
      in: path
      required: true
      schema:
        type: string
    AvailabilityId:
      name: availability_id
      in: path
      required: true
      schema:
        type: string
    AlertId:
      name: alert_id
      in: path
      required: true
      schema:
        type: string
    Cursor:
      name: cursor
      in: query
      required: false
      schema:
        type: string
    Limit:
      name: limit
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 50
  headers:
    FaFRequestId:
      schema:
        type: string
      description: Find a Flight request id.
    RateLimitRemaining:
      schema:
        type: integer
      description: Remaining requests in the current rate-limit window.
  responses:
    BadRequest:
      description: Request validation failed.
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ErrorResponse"
    Unauthorised:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ErrorResponse"
    Forbidden:
      description: Valid client but missing scope or entitlement.
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ErrorResponse"
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ErrorResponse"
    Conflict:
      description: Idempotency key conflict or resource conflict.
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ErrorResponse"
    RateLimited:
      description: Rate limit or quota exceeded.
      headers:
        Retry-After:
          schema:
            type: integer
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ErrorResponse"
  schemas:
    AirportCode:
      type: string
      pattern: "^[A-Z]{3}$"
      examples:
      - MEL
    CabinClass:
      type: string
      enum:
      - economy
      - premium_economy
      - business
      - first
    SearchRequest:
      type: object
      required:
      - origin
      - destinations
      - departure_date
      properties:
        origin:
          "$ref": "#/components/schemas/AirportCode"
        destinations:
          type: array
          minItems: 1
          maxItems: 25
          items:
            "$ref": "#/components/schemas/AirportCode"
        departure_date:
          type: string
          format: date
        flight_number:
          type: string
          pattern: "^[A-Z0-9]{2,8}$"
          description: Optional flight designator filter, for example QF408.
        return_date:
          type: string
          format: date
        cabin_classes:
          type: array
          minItems: 1
          items:
            "$ref": "#/components/schemas/CabinClass"
          default:
          - economy
          - premium_economy
          - business
          - first
        passengers:
          "$ref": "#/components/schemas/Passengers"
        programmes:
          type: array
          items:
            type: string
        airlines:
          type: array
          items:
            type: string
        max_points:
          type: integer
          minimum: 0
        max_cash:
          "$ref": "#/components/schemas/Money"
        nonstop_preferred:
          type: boolean
          default: false
        include_sold_out:
          type: boolean
          default: false
        locale:
          type: string
          examples:
          - en-AU
        currency:
          type: string
          examples:
          - AUD
        partner_context:
          "$ref": "#/components/schemas/PartnerContext"
    FlexibleSearchRequest:
      allOf:
      - "$ref": "#/components/schemas/SearchRequest"
      - type: object
        required:
        - date_range
        properties:
          date_range:
            type: object
            required:
            - start_date
            - end_date
            properties:
              start_date:
                type: string
                format: date
              end_date:
                type: string
                format: date
              flexibility_days:
                type: integer
                minimum: 0
                maximum: 30
    Passengers:
      type: object
      properties:
        adults:
          type: integer
          minimum: 1
          default: 1
        children:
          type: integer
          minimum: 0
          default: 0
        infants:
          type: integer
          minimum: 0
          default: 0
    PartnerContext:
      type: object
      additionalProperties: false
      properties:
        partner:
          type: object
          additionalProperties: false
          properties:
            partner_tenant_id:
              type: string
            partner_account_id:
              type: string
            partner_user_id_hash:
              type: string
            campaign_id:
              type: string
            offer_id:
              type: string
            attribution_source:
              type: string
        business:
          type: object
          additionalProperties: true
          properties:
            abn_token:
              type: string
            abn_classification:
              type: string
            type:
              type: string
            industry:
              type: string
            lifecycle_status:
              type: string
            account_tier:
              type: string
            value_segment:
              type: string
            advisor_type:
              type: string
        payments:
          type: object
          additionalProperties: true
          properties:
            volume_band:
              type: string
            transaction_count_band:
              type: string
            method_mix:
              type: array
              items:
                type: string
            category_mix:
              type: array
              items:
                type: string
            international_enabled:
              type: boolean
            currency_mix:
              type: array
              items:
                type: string
        rewards:
          type: object
          additionalProperties: true
          properties:
            balance_band:
              type: string
            earn_band:
              type: string
            spend_band:
              type: string
            expiry_risk:
              type: string
            earn_rate_tier:
              type: string
            preferred_transfer_partners:
              type: array
              items:
                type: string
            points_proficiency:
              type: string
        travel:
          type: object
          additionalProperties: true
          properties:
            home_airport:
              "$ref": "#/components/schemas/AirportCode"
            nearby_airports:
              type: array
              items:
                "$ref": "#/components/schemas/AirportCode"
            destination_regions:
              type: array
              items:
                type: string
            cabin_preference:
              type: array
              items:
                "$ref": "#/components/schemas/CabinClass"
            trip_purpose:
              type: string
            urgency:
              type: string
            paytravel_eligible:
              type: boolean
        consent:
          type: object
          additionalProperties: false
          properties:
            personalisation:
              type: boolean
            marketing:
              type: boolean
            data_sharing:
              type: boolean
            profiling:
              type: boolean
            do_not_personalise:
              type: boolean
        segments:
          type: object
          additionalProperties:
            oneOf:
            - type: string
            - type: array
              items:
                type: string
    SearchResponse:
      type: object
      required:
      - search_id
      - status
      - data
      properties:
        search_id:
          type: string
        status:
          "$ref": "#/components/schemas/JobStatus"
        data:
          type: array
          items:
            "$ref": "#/components/schemas/Availability"
        pagination:
          "$ref": "#/components/schemas/Pagination"
        usage:
          "$ref": "#/components/schemas/UsageCharge"
        warnings:
          type: array
          items:
            "$ref": "#/components/schemas/Caveat"
    Availability:
      type: object
      required:
      - availability_id
      - observed_at
      - source_type
      - confidence
      - programme
      - airline
      - route
      - cabin
      properties:
        availability_id:
          type: string
        search_id:
          type: string
        observed_at:
          type: string
          format: date-time
        stale_after:
          type: string
          format: date-time
        source:
          type: string
        source_type:
          type: string
          enum:
          - observed
          - cached
          - synthetic
          - indicative
          - live_refresh
        confidence:
          type: string
          enum:
          - high
          - medium
          - low
          - indicative
        programme:
          "$ref": "#/components/schemas/ProgrammeRef"
        airline:
          "$ref": "#/components/schemas/AirlineRef"
        operating_airline:
          "$ref": "#/components/schemas/AirlineRef"
        route:
          "$ref": "#/components/schemas/Route"
        cabin:
          "$ref": "#/components/schemas/CabinClass"
        seat_count:
          type:
          - integer
          - 'null'
          minimum: 0
        seat_count_kind:
          type: string
          enum:
          - exact
          - at_least
          - limited
          - available_unknown
          - sold_out
          - unavailable
          - unknown
        points_price:
          type:
          - integer
          - 'null'
          minimum: 0
        points_currency:
          type:
          - string
          - 'null'
        taxes_fees:
          "$ref": "#/components/schemas/Money"
        cash_price:
          "$ref": "#/components/schemas/Money"
        transfer_options:
          type: array
          items:
            "$ref": "#/components/schemas/TransferOption"
        payrewards_estimate:
          "$ref": "#/components/schemas/PayRewardsEstimate"
        booking_handoff:
          "$ref": "#/components/schemas/BookingHandoff"
        segments:
          type: array
          items:
            "$ref": "#/components/schemas/FlightSegment"
        caveats:
          type: array
          items:
            "$ref": "#/components/schemas/Caveat"
    Route:
      type: object
      required:
      - origin
      - destination
      properties:
        origin:
          "$ref": "#/components/schemas/AirportCode"
        destination:
          "$ref": "#/components/schemas/AirportCode"
        departure_at:
          type: string
          format: date-time
        arrival_at:
          type: string
          format: date-time
        duration_minutes:
          type: integer
          minimum: 0
        stops:
          type: integer
          minimum: 0
        stopover_airports:
          type: array
          items:
            "$ref": "#/components/schemas/AirportCode"
    FlightSegment:
      type: object
      properties:
        origin:
          "$ref": "#/components/schemas/AirportCode"
        destination:
          "$ref": "#/components/schemas/AirportCode"
        marketing_airline:
          type: string
        operating_airline:
          type: string
        flight_number:
          type: string
        departure_at:
          type: string
          format: date-time
        arrival_at:
          type: string
          format: date-time
        aircraft:
          type: string
    Money:
      type: object
      required:
      - amount
      - currency
      properties:
        amount:
          type: number
        currency:
          type: string
          minLength: 3
          maxLength: 3
    TransferOption:
      type: object
      required:
      - programme
      - supported
      properties:
        programme:
          "$ref": "#/components/schemas/ProgrammeRef"
        supported:
          type: boolean
        conversion_rate:
          type:
          - number
          - 'null'
        minimum_increment:
          type:
          - integer
          - 'null'
        caveats:
          type: array
          items:
            "$ref": "#/components/schemas/Caveat"
    PayRewardsEstimate:
      type: object
      properties:
        points_required:
          type: integer
        estimated_cost:
          "$ref": "#/components/schemas/Money"
        points_gap:
          type: integer
        earn_to_trip_estimate:
          type: object
          properties:
            payment_volume_required:
              "$ref": "#/components/schemas/Money"
            volume_band:
              type: string
    BookingHandoff:
      type: object
      properties:
        type:
          type: string
          enum:
          - airline_deep_link
          - partner_transfer
          - unsupported
        url:
          type:
          - string
          - 'null'
          format: uri
        allowed:
          type: boolean
        reason:
          type: string
    Programme:
      allOf:
      - "$ref": "#/components/schemas/ProgrammeRef"
      - type: object
        properties:
          transfer_partner:
            type: boolean
          currencies:
            type: array
            items:
              type: string
          supported:
            type: boolean
          caveats:
            type: array
            items:
              "$ref": "#/components/schemas/Caveat"
    ProgrammeRef:
      type: object
      required:
      - code
      - name
      properties:
        code:
          type: string
        name:
          type: string
    Airline:
      allOf:
      - "$ref": "#/components/schemas/AirlineRef"
      - type: object
        properties:
          supported:
            type: boolean
          live_refresh_supported:
            type: boolean
          source_types:
            type: array
            items:
              type: string
    AirlineRef:
      type: object
      required:
      - code
      - name
      properties:
        code:
          type: string
        name:
          type: string
    CoverageItem:
      type: object
      required:
      - programme
      - airline
      - status
      properties:
        programme:
          "$ref": "#/components/schemas/ProgrammeRef"
        airline:
          "$ref": "#/components/schemas/AirlineRef"
        status:
          type: string
          enum:
          - supported
          - cached_only
          - live_refresh_only
          - indicative_only
          - unsupported
        source_types:
          type: array
          items:
            type: string
        freshness_sla_minutes:
          type:
          - integer
          - 'null'
        caveats:
          type: array
          items:
            "$ref": "#/components/schemas/Caveat"
    RefreshRequest:
      type: object
      required:
      - target
      properties:
        target:
          type: object
          oneOf:
          - required:
            - availability_id
          - required:
            - route
          properties:
            availability_id:
              type: string
            route:
              "$ref": "#/components/schemas/Route"
            programme:
              type: string
            cabin:
              "$ref": "#/components/schemas/CabinClass"
        reason:
          type: string
        partner_context:
          "$ref": "#/components/schemas/PartnerContext"
    RefreshStatus:
      allOf:
      - "$ref": "#/components/schemas/AsyncJob"
      - type: object
        properties:
          availability:
            "$ref": "#/components/schemas/Availability"
    AsyncJob:
      type: object
      required:
      - id
      - status
      - created_at
      properties:
        id:
          type: string
        status:
          "$ref": "#/components/schemas/JobStatus"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        poll_after_ms:
          type: integer
          minimum: 0
        links:
          type: object
          properties:
            self:
              type: string
              format: uri
    JobStatus:
      type: string
      enum:
      - queued
      - running
      - completed
      - partial
      - failed
      - cancelled
      - expired
    AlertCreateRequest:
      type: object
      required:
      - name
      - search
      properties:
        name:
          type: string
        search:
          "$ref": "#/components/schemas/SearchRequest"
        cadence:
          type: string
          enum:
          - hourly
          - daily
          - weekly
          default: daily
        expires_at:
          type: string
          format: date-time
        webhook_events:
          type: array
          items:
            type: string
            enum:
            - alert.matched
            - alert.expired
    AlertUpdateRequest:
      type: object
      properties:
        name:
          type: string
        status:
          type: string
          enum:
          - active
          - paused
          - expired
        expires_at:
          type: string
          format: date-time
    Alert:
      type: object
      required:
      - id
      - name
      - status
      - created_at
      properties:
        id:
          type: string
        name:
          type: string
        status:
          type: string
          enum:
          - active
          - paused
          - expired
        search:
          "$ref": "#/components/schemas/SearchRequest"
        created_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
    WebhookEndpointCreateRequest:
      type: object
      required:
      - url
      - event_types
      properties:
        url:
          type: string
          format: uri
        event_types:
          type: array
          minItems: 1
          items:
            "$ref": "#/components/schemas/WebhookEventType"
        description:
          type: string
    WebhookEndpointCreateResponse:
      type: object
      required:
      - endpoint
      - signing_secret
      properties:
        endpoint:
          "$ref": "#/components/schemas/WebhookEndpoint"
        signing_secret:
          type: string
          description: Returned once. Store securely.
    WebhookEndpoint:
      type: object
      required:
      - id
      - url
      - status
      - event_types
      - created_at
      properties:
        id:
          type: string
        url:
          type: string
          format: uri
        status:
          type: string
          enum:
          - active
          - disabled
        event_types:
          type: array
          items:
            "$ref": "#/components/schemas/WebhookEventType"
        created_at:
          type: string
          format: date-time
    WebhookEvent:
      type: object
      required:
      - id
      - type
      - created_at
      - data
      properties:
        id:
          type: string
        type:
          "$ref": "#/components/schemas/WebhookEventType"
        created_at:
          type: string
          format: date-time
        data:
          type: object
          additionalProperties: true
        delivery_status:
          type: string
          enum:
          - pending
          - delivered
          - failed
          - disabled
    WebhookEventType:
      type: string
      enum:
      - search.completed
      - search.failed
      - refresh.completed
      - refresh.failed
      - alert.matched
      - alert.expired
      - usage.threshold_reached
      - entitlement.updated
    UsageSummary:
      type: object
      required:
      - period
      - units_used
      - units_included
      - endpoints
      properties:
        period:
          type: string
        units_used:
          type: number
        units_included:
          type: number
        units_remaining:
          type: number
        endpoints:
          type: array
          items:
            type: object
            required:
            - endpoint
            - requests
            - units
            properties:
              endpoint:
                type: string
              requests:
                type: integer
              units:
                type: number
              error_rate:
                type: number
        rate_limits:
          type: array
          items:
            "$ref": "#/components/schemas/RateLimit"
    Entitlements:
      type: object
      required:
      - plan
      - environment
      - scopes
      properties:
        plan:
          type: string
        environment:
          type: string
          enum:
          - sandbox
          - production
        scopes:
          type: array
          items:
            type: string
        monthly_units:
          type: integer
        live_refresh_units:
          type: integer
        alert_limit:
          type: integer
        webhook_endpoint_limit:
          type: integer
        programme_allowlist:
          type: array
          items:
            type: string
        airline_allowlist:
          type: array
          items:
            type: string
        rate_limits:
          type: array
          items:
            "$ref": "#/components/schemas/RateLimit"
    RateLimit:
      type: object
      required:
      - name
      - limit
      - window_seconds
      properties:
        name:
          type: string
        limit:
          type: integer
        remaining:
          type: integer
        window_seconds:
          type: integer
        reset_at:
          type: string
          format: date-time
    UsageCharge:
      type: object
      required:
      - units
      - unit_type
      properties:
        units:
          type: number
        unit_type:
          type: string
        live_refresh_units:
          type: number
        cache_units:
          type: number
    Pagination:
      type: object
      properties:
        cursor:
          type: string
        next_cursor:
          type:
          - string
          - 'null'
        has_more:
          type: boolean
    Caveat:
      type: object
      required:
      - code
      - message
      properties:
        code:
          type: string
        message:
          type: string
        severity:
          type: string
          enum:
          - info
          - warning
          - error
    ErrorResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
              examples:
              - invalid_request
            message:
              type: string
            request_id:
              type: string
            details:
              type: array
              items:
                type: object
                additionalProperties: true
