openapi: 3.0.3
info:
  title: BookDirect Middleware — lodging v1
  version: 1.0.0
  description: |
    API-first contract for HTTP processors. Implement as Nest route folders.
    Persist on Core — do not use Mongo as source of truth.
    Scheduled / queue workers (abandon holds, ARI reconcile, email retry) are
    internal — not listed as public paths. See docs/v1/middleware/processors-and-workers.md.
    Live explorer (may lag this spec): https://middleware-dev.bookdirect.live/docs/api#/
servers:
  - url: https://middleware-dev.bookdirect.live
    description: BookDirect middleware dev
tags:
  - name: Availability
  - name: Payments
  - name: Refunds
  - name: Emails
  - name: GoogleRates
  - name: FileManager
paths:
  /api/v1/bookdirect/availability/check:
    post:
      tags: [Availability]
      operationId: checkAvailability
      summary: Date-overlap availability (counts only, no guest PII)
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [property_uuid, check_in, check_out]
              properties:
                property_uuid: { type: string, format: uuid }
                check_in: { type: string, format: date }
                check_out: { type: string, format: date }
                units_needed: { type: integer, default: 1 }
      responses:
        '200':
          description: Remaining units per rate plan
  /api/v1/bookdirect/payments/initialize:
    post:
      tags: [Payments]
      operationId: initializePayment
      summary: Start PSP checkout; writes Core payment entity
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [booking_uuid, provider, amount_kobo, currency]
              properties:
                booking_uuid: { type: string, format: uuid }
                provider: { type: string, enum: [paystack, squad, tsara] }
                amount_kobo: { type: integer }
                currency: { type: string, example: NGN }
                callback_url: { type: string, format: uri }
      responses:
        '200':
          description: authorization_url, reference, payment_uuid
  /api/v1/bookdirect/payments/verify/{reference}:
    post:
      tags: [Payments]
      operationId: verifyPayment
      security:
        - BearerAuth: []
      parameters:
        - name: reference
          in: path
          required: true
          schema: { type: string }
      responses:
        '200': { description: Confirms Core payment + booking if paid }
  /api/v1/bookdirect/payments/webhook/paystack:
    post:
      tags: [Payments]
      operationId: paystackWebhook
      summary: PSP signature only — no user JWT
      security: []
      responses:
        '200': { description: ACK }
  /api/v1/bookdirect/refunds:
    post:
      tags: [Refunds]
      operationId: createRefund
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [booking_uuid]
              properties:
                booking_uuid: { type: string, format: uuid }
                reason: { type: string }
                amount_kobo: { type: integer, nullable: true }
      responses:
        '200': { description: Refund started; Core updated }
  /api/v1/bookdirect/refunds/{refund_uuid}:
    get:
      tags: [Refunds]
      operationId: getRefund
      security:
        - BearerAuth: []
      parameters:
        - name: refund_uuid
          in: path
          required: true
          schema: { type: string, format: uuid }
      responses:
        '200': { description: Refund status }
  /api/v1/bookdirect/emails/send:
    post:
      tags: [Emails]
      operationId: sendEmail
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [template, booking_uuid]
              properties:
                template:
                  type: string
                  enum:
                    - booking_pending_guest
                    - booking_confirmed_guest
                    - booking_confirmed_owner
                    - booking_cancelled_guest
                    - booking_cancelled_owner
                booking_uuid: { type: string, format: uuid }
      responses:
        '200': { description: Queued or sent }
  /api/v1/bookdirect/google-rates/push:
    post:
      tags: [GoogleRates]
      operationId: pushGoogleRates
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [property_uuid]
              properties:
                property_uuid: { type: string, format: uuid }
                from: { type: string, format: date }
                to: { type: string, format: date }
      responses:
        '200': { description: ARI push accepted }
  /api/v1/bookdirect/google-rates/pull:
    post:
      tags: [GoogleRates]
      operationId: pullGoogleRates
      security:
        - BearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [property_uuid]
              properties:
                property_uuid: { type: string, format: uuid }
      responses:
        '200': { description: Rates; persist on Core rate_plan if needed }
  /api/v1/bookdirect/google-rates/status/{property_uuid}:
    get:
      tags: [GoogleRates]
      operationId: googleRatesStatus
      security:
        - BearerAuth: []
      parameters:
        - name: property_uuid
          in: path
          required: true
          schema: { type: string, format: uuid }
      responses:
        '200': { description: Last push/pull status }
  /api/v1/nellalink/file-manager/aws/upload-url:
    post:
      tags: [FileManager]
      operationId: createUploadUrl
      summary: Live — presigned S3 upload
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [files]
              properties:
                files:
                  type: array
                  items:
                    type: object
                    required: [file_name, file_size]
                    properties:
                      file_name: { type: string }
                      file_type: { type: string }
                      file_size: { type: integer }
                      visibility: { type: string, enum: [public, private] }
                      directory: { type: string }
                expires_in: { type: integer }
      responses:
        '200': { description: Presigned URLs }
  /api/v1/nellalink/file-manager/aws/download-url:
    post:
      tags: [FileManager]
      operationId: createDownloadUrl
      security:
        - BearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required: [files]
              properties:
                files:
                  type: array
                  items: { type: string }
                expires_in: { type: integer }
      responses:
        '200': { description: Presigned download URLs }
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Same Nellalink JWT as Core (iss=nellalink)
