openapi: 3.1.0
info:
  title: DialStack Partner API
  version: 1.0.0
  description: |
    Partner API for voice AI bots to search availability and book appointments.

    ## Authentication
    Use your partner API key (starts with `sk_ptnr_`) in the Authorization header:

    ```
    Authorization: Bearer sk_ptnr_YOUR_PARTNER_KEY
    ```

    ## Base URL
    - `https://appointments.dialstack.ai`

    ## How It Works
    1. Partner sends request to DialStack with `bot_id`
    2. DialStack looks up the bot and its associated account
    3. DialStack relays the request to the platform's webhook (if configured)
    4. Platform response is passed through to the partner

    ## Error Handling
    All errors follow a consistent format:
    ```json
    {
      "error": {
        "code": "error_code",
        "message": "Human-readable message"
      }
    }
    ```

  contact:
    name: DialStack API Support
    email: info@dialstack.ai
    url: https://docs.dialstack.ai

servers:
  - url: https://appointments.dialstack.ai
    description: Production

security:
  - PartnerAuth: []

components:
  securitySchemes:
    PartnerAuth:
      type: http
      scheme: bearer
      bearerFormat: sk_ptnr_*
      description: |
        Partner API key (starts with `sk_ptnr_`) for voice AI bot integrations.
        Include in Authorization header:
        `Authorization: Bearer sk_ptnr_YOUR_PARTNER_KEY`

  schemas:
    # Request schemas
    AvailabilitySearchRequest:
      type: object
      required:
        - bot_id
        - query
      properties:
        bot_id:
          type: string
          description: The bot ID making the request
          example: 'bot_01h2xcejqtf2nbrexx3vqjhp41'
        query:
          $ref: '#/components/schemas/AvailabilityQuery'

    AvailabilityQuery:
      type: object
      required:
        - filter
      properties:
        filter:
          $ref: '#/components/schemas/AvailabilityFilter'

    AvailabilityFilter:
      type: object
      required:
        - start_at_range
      properties:
        start_at_range:
          type: object
          description: Time range to search for availability
          required:
            - start_at
            - end_at
          properties:
            start_at:
              type: string
              format: date-time
              description: Start of the search range (ISO 8601)
              example: '2024-01-15T09:00:00Z'
            end_at:
              type: string
              format: date-time
              description: End of the search range (ISO 8601)
              example: '2024-01-15T17:00:00Z'

    CreateBookingRequest:
      type: object
      required:
        - bot_id
        - booking
      properties:
        bot_id:
          type: string
          description: The bot ID making the request
          example: 'bot_01h2xcejqtf2nbrexx3vqjhp41'
        booking:
          $ref: '#/components/schemas/BookingDetails'

    BookingDetails:
      type: object
      required:
        - start_at
        - duration_minutes
        - customer
      properties:
        start_at:
          type: string
          format: date-time
          description: Appointment start time (ISO 8601)
          example: '2024-01-15T10:00:00Z'
        duration_minutes:
          type: integer
          minimum: 1
          description: Duration of the appointment in minutes
          example: 30
        customer:
          $ref: '#/components/schemas/CustomerDetails'
        notes:
          type:
            - string
            - 'null'
          description: Additional notes for the appointment
          example: 'Initial consultation - referred by AI assistant'

    CustomerDetails:
      type: object
      required:
        - phone
        - name
      properties:
        phone:
          type: string
          description: Customer phone number (E.164 format recommended)
          example: '+15551234567'
        name:
          type: string
          description: Customer name
          example: 'John Doe'
        email:
          type:
            - string
            - 'null'
          format: email
          description: Customer email address
          example: 'john@example.com'

    # Response schemas (pass-through from platform)
    AvailabilitySearchResponse:
      type: object
      required:
        - availabilities
      properties:
        availabilities:
          type: array
          items:
            $ref: '#/components/schemas/Availability'

    Availability:
      type: object
      required:
        - start_at
        - duration_minutes
      properties:
        start_at:
          type: string
          format: date-time
          description: Available slot start time
          example: '2024-01-15T10:00:00Z'
        duration_minutes:
          type: integer
          description: Slot duration in minutes
          example: 30

    BookingResponse:
      type: object
      required:
        - booking
      properties:
        booking:
          type: object
          properties:
            id:
              type: string
              description: Booking ID from the platform
              example: 'bkg_01h2xcejqtf2nbrexx3vqjhp41'
            status:
              type: string
              enum:
                - confirmed
                - pending
              description: Booking status
              example: 'confirmed'
            start_at:
              type: string
              format: date-time
              example: '2024-01-15T10:00:00Z'
            end_at:
              type: string
              format: date-time
              example: '2024-01-15T10:30:00Z'
            customer:
              type: object
              properties:
                phone:
                  type: string
                  example: '+15551234567'
                name:
                  type: string
                  example: 'John Doe'
            location:
              type: object
              properties:
                name:
                  type: string
                  example: 'Main Office'
                address:
                  type: string
                  example: '123 Main St, City, ST 12345'
            notes:
              type: string
              description: Additional booking information such as assigned provider
              example: 'Provider: Dr. Chen (Sports Medicine)'
            created_at:
              type: string
              format: date-time
              example: '2024-01-10T14:30:00Z'

    # Error schemas
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code
              example: 'bot_not_found'
            message:
              type: string
              description: Human-readable error message
              example: "Bot not found or doesn't belong to partner"
            details:
              type: object
              description: Additional error details
              additionalProperties: true

  responses:
    Unauthorized:
      description: Authentication failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'unauthorized'
              message: 'Invalid or missing API key'

    NotFound:
      description: Bot not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'bot_not_found'
              message: "Bot not found or doesn't belong to partner"

    Forbidden:
      description: Bot is disabled
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'bot_disabled'
              message: 'Bot is not active'

    BadGateway:
      description: Platform webhook error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'platform_error'
              message: 'Platform webhook returned an error'

    GatewayTimeout:
      description: Platform webhook timeout
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'platform_timeout'
              message: 'Platform webhook timed out'

paths:
  /v1/availability/search:
    post:
      summary: Search availability
      description: |
        Search for available appointment slots.

        The request is relayed to the platform's webhook endpoint. The response
        format depends on the platform's implementation.
      operationId: searchAvailability
      tags:
        - Appointments
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AvailabilitySearchRequest'
            example:
              bot_id: 'bot_01h2xcejqtf2nbrexx3vqjhp41'
              query:
                filter:
                  start_at_range:
                    start_at: '2024-01-15T09:00:00Z'
                    end_at: '2024-01-15T17:00:00Z'
      responses:
        '200':
          description: Available slots (pass-through from platform)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AvailabilitySearchResponse'
              example:
                availabilities:
                  - start_at: '2024-01-15T10:00:00Z'
                    duration_minutes: 30
                  - start_at: '2024-01-15T10:30:00Z'
                    duration_minutes: 30
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: 'invalid_request'
                  message: 'Invalid bot_id format'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '502':
          $ref: '#/components/responses/BadGateway'
        '504':
          $ref: '#/components/responses/GatewayTimeout'

  /v1/bookings:
    post:
      summary: Create booking
      description: |
        Book an appointment slot.

        Requires an `Idempotency-Key` header to ensure the booking is not
        duplicated if the request is retried.

        The request is relayed to the platform's webhook endpoint. The response
        format depends on the platform's implementation.
      operationId: createBooking
      tags:
        - Appointments
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: |
            Unique key to ensure idempotent booking creation.
            If the same key is used again, the original booking is returned.
          schema:
            type: string
          example: 'booking-req-123456'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBookingRequest'
            example:
              bot_id: 'bot_01h2xcejqtf2nbrexx3vqjhp41'
              booking:
                start_at: '2024-01-15T10:00:00Z'
                duration_minutes: 30
                customer:
                  phone: '+15551234567'
                  name: 'John Doe'
                  email: 'john@example.com'
                notes: 'Initial consultation - referred by AI assistant'
      responses:
        '200':
          description: Booking created (pass-through from platform)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BookingResponse'
              example:
                booking:
                  id: 'bkg_01h2xcejqtf2nbrexx3vqjhp41'
                  status: 'confirmed'
                  start_at: '2024-01-15T10:00:00Z'
                  end_at: '2024-01-15T10:30:00Z'
                  customer:
                    phone: '+15551234567'
                    name: 'John Doe'
                  location:
                    name: 'Main Office'
                    address: '123 Main St, City, ST 12345'
                  created_at: '2024-01-10T14:30:00Z'
        '400':
          description: Invalid request (missing Idempotency-Key or malformed body)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: 'invalid_request'
                  message: 'Idempotency-Key header is required'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Time slot no longer available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: 'slot_unavailable'
                  message: 'The requested time slot is no longer available'
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: 'validation_error'
                  message: 'booking.customer.phone is required'
        '502':
          $ref: '#/components/responses/BadGateway'
        '504':
          $ref: '#/components/responses/GatewayTimeout'

tags:
  - name: Appointments
    description: |
      Appointment booking endpoints for voice AI partners.

      These endpoints allow voice AI bots to search for available appointment
      slots and create bookings on behalf of end customers.
