> ## Documentation Index
> Fetch the complete documentation index at: https://opencals.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get appointment by ID

> Returns a single appointment by ID for the authenticated customer



## OpenAPI

````yaml /api-reference/openapi.json get /storefront/appointments/{appointmentId}
openapi: 3.0.0
info:
  title: Opencals API
  description: >
    # Opencals Storefront API


    Build custom booking storefronts with the Opencals Storefront API. Browse
    services, check real-time availability, manage carts, process payments, and
    complete bookings — all programmatically.


    ---


    ## Getting Started


    ### 1. Create an Account


    Sign up at [app.opencals.com](https://app.opencals.com) and set up your
    store with services, staff members, locations, and schedules.


    ### 2. Generate a Storefront API Key


    Navigate to **Settings > API Keys** in your dashboard. Create a new
    **Storefront API Key**. Each key is scoped to your store and starts with
    `sfk_`.


    ### 3. Make Your First Request


    ```bash

    curl -H "X-Api-Key: sfk_your_key_here" \
      https://api.opencals.com/customer/products
    ```


    This returns a paginated list of your store's active services.


    ---


    ## Authentication


    ### Storefront API Key


    All requests require a **Storefront API Key** in the `X-Api-Key` header:


    ```

    X-Api-Key: sfk_your_key_here

    ```


    This key identifies your store. It should be kept server-side (e.g., in
    environment variables) and never exposed to the browser.


    ### Customer Authentication


    Some endpoints require a logged-in customer (viewing appointments, managing
    profile). Customers authenticate via credentials and receive JWT tokens:


    ```http

    POST /auth/customer/sign-in

    X-Api-Key: sfk_your_key_here

    Content-Type: application/json


    {
      "email": "customer@example.com",
      "password": "securepassword"
    }

    ```


    **Response:**

    ```json

    {
      "accessToken": "eyJhbGciOi...",
      "refreshToken": "eyJhbGciOi..."
    }

    ```


    Include the customer token alongside the API key for authenticated requests:

    ```

    Authorization: Bearer <customer_access_token>

    X-Api-Key: sfk_your_key_here

    ```


    ### Customer Auth Endpoints


    | Method | Endpoint | Description |

    |--------|----------|-------------|

    | `POST` | `/auth/customer/sign-up` | Register a new customer (sends
    verification email) |

    | `POST` | `/auth/customer/sign-in` | Sign in with email + password |

    | `POST` | `/auth/customer/oauth` | Sign in/register via OAuth provider
    (e.g., Google) |

    | `POST` | `/auth/customer/verify-email` | Verify email with token from
    verification email |

    | `POST` | `/auth/customer/request-email-verification` | Resend verification
    email |

    | `POST` | `/auth/customer/request-password-reset` | Send password reset
    email |

    | `POST` | `/auth/customer/reset-password` | Reset password with token |

    | `GET`  | `/auth/customer/refresh` | Refresh tokens (pass refresh token as
    Bearer) |


    ---


    ## Booking Flows


    The booking flow depends on your product configuration. Below are the common
    patterns.


    ### Standard Booking (Single Time Slot)


    The most common flow — customer picks a service, selects a date/time, and
    books.


    ```

    1. GET  /customer/products                              → Browse services

    2. GET  /customer/products/:id/current-availabilities    → Get available
    time slots for a date
          ?date=2026-06-15&timezone=America/New_York
    3. POST /customer/appointments                           → Create
    appointment with chosen slot
          { slot: { productId, fromDate, fromTime, toDate, toTime }, numberOfAttendees: 1 }
    4. POST /customer/cart                                   → Create or get
    cart

    5. POST /customer/cart/items                             → Add appointment
    to cart
          { appointmentId: "..." }
    6. POST /customer/cart/checkout/start                    → Start checkout
    with payment provider
          { provider: "stripe" }
    7. POST /customer/cart/checkout/save-customer            → Save customer
    info
          { customer: { email, firstName, lastName } }
    8. POST /customer/cart/checkout/submit                   → Complete booking
    & capture payment

    ```


    ### Custom Duration / Date Range Booking


    When a product has **custom duration** enabled (e.g., car rentals, venue
    bookings), customers select a date range instead of a single time slot.


    **How to detect:** The product's `isCustomDuration` field is `true`.


    ```

    1. GET /customer/products/:id/current-availability-ranges   → Get available
    date ranges
          ?timezone=America/New_York
    2. UI shows a date range picker instead of individual slots

    3. POST /customer/appointments
          { slot: { productId, fromDate: "2026-06-15", fromTime: "09:00:00",
                    toDate: "2026-06-18", toTime: "17:00:00" } }
    4. Continue with cart → checkout flow as above

    ```


    ### Group Appointments


    When a product supports multiple attendees (`maxAttendees > 1`), display an
    attendees selector.


    ```

    POST /customer/appointments

    {
      "slot": { ... },
      "numberOfAttendees": 4
    }

    ```


    ### Location-First Flow


    When a store has multiple locations, let the customer pick a location first,
    then filter services and availability by location.


    ```

    1. GET /customer/locations                                → List all
    locations

    2. User selects a location

    3. GET /customer/products?locationId=<locationId>         → Products at that
    location

    4. GET /customer/products/:id/current-availabilities
          ?date=2026-06-15&locationId=<locationId>            → Slots at that location
    5. POST /customer/appointments
          { slot: { ..., locationId: "<locationId>" } }
    ```


    ### Staff-First Flow


    When staff member selection is important (e.g., hair salons), let customers
    choose their preferred staff member.


    ```

    1. GET /customer/staff-members                            → List staff
    members

    2. User selects a staff member

    3. GET /customer/products/:id/current-availabilities
          ?date=2026-06-15&staffMemberId=<staffMemberId>      → Slots with that staff member
    4. POST /customer/appointments
          { slot: { ..., staffMemberId: "<staffMemberId>" } }
    ```


    ### Combined Flow (Location + Staff + Service)


    All filters can be combined:


    ```

    GET /customer/products/:id/current-availabilities
        ?date=2026-06-15
        &locationId=<locationId>
        &staffMemberId=<staffMemberId>
        &timezone=America/New_York
    ```


    ---


    ## Product Configuration Flags


    Products have configuration fields that determine which UI elements to
    display. Check these fields when rendering your booking interface:


    | Field | Type | UI Behavior |

    |-------|------|-------------|

    | `isCustomDuration` | `boolean` | `true` → show date range picker; `false`
    → show single time slot picker |

    | `maxAttendees` | `number` | `> 1` → show attendees selector; `1` → hide it
    |

    | `skipCheckout` | `boolean` | `true` → skip payment step, book directly;
    `false` → normal checkout |

    | `fixedStartTimes` / `fixedEndTimes` | `string[]` | If present, only these
    specific times are bookable |

    | `locations` | `Location[]` | If populated, show location selector |

    | `staffMembers` | `StaffMember[]` | If populated, show staff member
    selector |

    | `price` | `number` | Service price; `0` = free |

    | `minPrice` / `maxPrice` | `number` | Price range for variable-priced
    services |

    | `duration` | `number` | Service duration in seconds |

    | `minDuration` / `maxDuration` | `number` | Duration range for custom
    duration services |

    | `images` | `Image[]` | Product images for gallery display |

    | `description` | `string` | Product description (may contain markdown) |


    ---


    ## Endpoint Reference


    ### Products


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/products` | API key | List all active products
    (paginated) |

    | `GET` | `/customer/products/:id` | API key | Get product by ID |

    | `GET` | `/customer/products/slug/:slug` | API key | Get product by URL
    slug |

    | `GET` | `/customer/products/:id/current-availabilities` | API key | Get
    bookable time slots for a date |

    | `GET` | `/customer/products/:id/current-availability-ranges` | API key |
    Get available date ranges (for custom duration) |

    | `GET` | `/customer/products/:id/nearest-availability` | API key | Find
    next available slot |


    **Availability query parameters:**


    | Parameter | Required | Description |

    |-----------|----------|-------------|

    | `date` | Yes (for current-availabilities) | Date in `YYYY-MM-DD` format |

    | `locationId` | No | Filter by location |

    | `staffMemberId` | No | Filter by staff member |

    | `timezone` | No | Timezone for date/time calculations (e.g.,
    `America/New_York`) |


    ### Product Collections


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/product-collections` | API key | List all collections
    (paginated) |

    | `GET` | `/customer/product-collections/slug/:slug` | API key | Get
    collection by slug |


    ### Locations


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/locations` | API key | List all locations (paginated) |

    | `GET` | `/customer/locations/:id` | API key | Get location by ID |

    | `GET` | `/customer/locations/slug/:slug` | API key | Get location by slug
    |


    ### Staff Members


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/staff-members` | API key | List all staff members
    (paginated) |

    | `GET` | `/customer/staff-members/slug/:slug` | API key | Get staff member
    by slug |


    ### Cart


    All cart endpoints use the `X-Cart-Id` header to identify the cart.


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `POST` | `/customer/cart` | API key | Create or retrieve a cart |

    | `GET` | `/customer/cart` | API key | Get current cart |

    | `POST` | `/customer/cart/items` | API key | Add an appointment to the cart
    |

    | `DELETE` | `/customer/cart/items/:itemId` | API key | Remove item from
    cart |

    | `POST` | `/customer/cart/extend` | API key | Extend cart expiration (5
    min) |


    **Adding items to cart:**

    ```json

    POST /customer/cart/items

    X-Cart-Id: <cart_id>


    { "appointmentId": "appointment-uuid-here" }

    ```


    ### Add-Ons


    Add-ons are optional extras customers can attach to a cart item at checkout
    (equipment rentals, upgrades, accessories, etc.). Add-ons are scoped to
    products — only add-ons assigned to the booked service appear.


    **Storefront (listing):**


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/storefront/add-ons` | API key | List add-ons (filter by
    `productId`) |

    | `GET` | `/storefront/add-ons/:id` | API key | Get add-on by ID |

    | `GET` | `/storefront/add-ons/slug/:slug` | API key | Get add-on by slug |

    | `GET` | `/storefront/products/:id/add-ons` | API key | List add-ons for a
    specific product |


    **Cart (selection):**


    All cart add-on endpoints require the `X-Cart-Id` header.


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `POST` | `/storefront/cart/add-ons` | API key | Add an add-on to a cart
    item |

    | `PATCH` | `/storefront/cart/add-ons/:id` | API key | Update add-on
    quantity |

    | `DELETE` | `/storefront/cart/add-ons/:id` | API key | Remove add-on from
    cart |


    **Adding an add-on to a cart item:**

    ```json

    POST /storefront/cart/add-ons

    X-Cart-Id: <cart_id>


    {
      "cartItemId": "uuid-of-cart-item",
      "addOnId": "uuid-of-add-on",
      "quantity": 1
    }

    ```


    The system validates that the add-on is assigned to the cart item's product
    and that `quantity` does not exceed `maxQuantity` (if set). For
    duration-multiplied add-ons, quantity is auto-set to match the service
    duration units — send any value and it will be overridden.


    **Add-on object (storefront response):**

    ```json

    {
      "id": "addon-uuid",
      "slug": "deep-conditioning",
      "title": "Deep Conditioning Treatment",
      "description": "Intensive moisture treatment added to any color or cut service.",
      "price": 20.00,
      "taxable": true,
      "durationMultiplied": false,
      "maxQuantity": 1,
      "status": "active",
      "imageId": "img-uuid-or-null"
    }

    ```


    **Pricing notes:**

    - `price` — unit price. For duration-multiplied add-ons, multiply by
    duration units to get the total.

    - `durationMultiplied: true` — quantity is auto-set to the number of
    base-duration units booked (useful for per-day or per-hour charges).

    - Prices are snapshotted at cart/order creation. Later catalog price changes
    do not affect existing orders.


    **In the order response**, add-ons appear as `addOnLineItems` on each line
    item:

    ```json

    {
      "lineItems": [
        {
          "id": "...",
          "appointmentId": "...",
          "addOnLineItems": [
            {
              "id": "...",
              "addOnId": "...",
              "title": "Deep Conditioning Treatment",
              "quantity": 1,
              "originalUnitPrice": 20.00,
              "unitTaxAmount": 3.33,
              "totalPrice": 20.00
            }
          ]
        }
      ]
    }

    ```


    ### Checkout


    All checkout endpoints require the `X-Cart-Id` header.


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `POST` | `/customer/cart/checkout/start` | API key | Start checkout
    (initialize payment) |

    | `POST` | `/customer/cart/checkout/save-customer` | API key | Save customer
    info to cart |

    | `GET` | `/customer/cart/checkout/questions/:language` | API key | Get
    checkout questions |

    | `POST` | `/customer/cart/checkout/save-answers` | API key | Save checkout
    question answers |

    | `POST` | `/customer/cart/checkout/submit` | API key | Submit checkout
    (capture payment, create order) |


    **Start checkout:**

    ```json

    POST /customer/cart/checkout/start

    X-Cart-Id: <cart_id>


    {
      "provider": "stripe",
      "customer": {
        "email": "john@example.com",
        "firstName": "John",
        "lastName": "Smith"
      }
    }

    ```


    The `provider` field accepts: `stripe`, `cash`, or other configured payment
    providers.


    **Submit checkout response** includes order details and optionally
    auto-generated customer auth tokens:

    ```json

    {
      "order": { "id": "...", "name": "#1001", ... },
      "tokens": {
        "accessToken": "eyJ...",
        "refreshToken": "eyJ..."
      }
    }

    ```


    ### Appointments (Customer Authenticated)


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `POST` | `/customer/appointments` | API key (+ optional customer token) |
    Create appointment |

    | `GET` | `/customer/appointments` | Customer token | List customer
    appointments (paginated) |

    | `GET` | `/customer/appointments/:id` | Customer token | Get appointment
    details |

    | `PUT` | `/customer/appointments/:id/reschedule` | Customer token |
    Reschedule appointment |

    | `PUT` | `/customer/appointments/:id/cancel` | Customer token | Cancel
    appointment |

    | `POST` | `/customer/appointments/:id/feedback` | Customer token | Submit
    feedback |

    | `GET` | `/customer/appointments/preferences/booking-history` | Customer
    token | Get booking preferences |


    ### Orders (Customer Authenticated)


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/orders` | Customer token | List customer orders
    (paginated) |

    | `GET` | `/customer/orders/:id` | Customer token | Get order details |


    ### Customer Profile (Customer Authenticated)


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/profile` | Customer token | Get customer profile |

    | `PUT` | `/customer/profile` | Customer token | Update customer profile |

    | `PUT` | `/customer/password` | Customer token | Change password |


    ### Store


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/stores/public-settings` | API key | Get store public
    settings |


    **Public settings response includes:**

    - `name` — store display name

    - `domain` — store domain

    - `currency` — store currency code (e.g., `USD`)

    - `settings` — general store settings (timezone, locale, etc.)

    - `storefrontSettings` — presentation config (logo, colors, banners, etc.)

    - `contactInfo` — store contact information

    - `features` — enabled plan features


    ### Payment


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/payment/providers` | API key | List available payment
    providers |

    | `GET` | `/customer/payment/settings` | API key | Get public payment
    settings |


    ### Images


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/images/:id` | API key | Get image metadata by ID |


    ### Checkout Questions


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/checkout-questions/:productId/translations/:language` |
    API key | Get checkout questions for a product |


    ### Feedback Questions


    | Method | Endpoint | Auth | Description |

    |--------|----------|------|-------------|

    | `GET` | `/customer/feedback-questions/:productId/translations/:language` |
    Customer token | Get feedback questions for a product |


    ---


    ## Checkout Flow Detail


    ### Step 1: Create Appointment


    Before adding to a cart, create the appointment with the selected time slot:


    ```json

    POST /customer/appointments

    {
      "slot": {
        "productId": "product-uuid",
        "fromDate": "2026-06-15",
        "fromTime": "09:00:00",
        "toDate": "2026-06-15",
        "toTime": "10:00:00",
        "locationId": "location-uuid-or-null",
        "staffMemberId": "staff-uuid-or-null"
      },
      "numberOfAttendees": 1
    }

    ```


    All date/time values are in **UTC**. Convert from the user's timezone before
    sending.


    ### Step 2: Create Cart & Add Items


    ```json

    POST /customer/cart

    → Returns { "id": "cart-uuid", ... }


    POST /customer/cart/items

    X-Cart-Id: cart-uuid

    { "appointmentId": "appointment-uuid" }

    ```


    Carts expire automatically. Use `POST /customer/cart/extend` to add 5
    minutes.


    ### Step 3: Start Checkout


    ```json

    POST /customer/cart/checkout/start

    X-Cart-Id: cart-uuid

    {
      "provider": "stripe",
      "customer": { "email": "john@example.com", "firstName": "John", "lastName": "Smith" }
    }

    ```


    Response includes payment provider details (e.g., Stripe `clientSecret` for
    Elements).


    ### Step 4: Save Customer Info


    If not provided in start, save customer details separately:


    ```json

    POST /customer/cart/checkout/save-customer

    X-Cart-Id: cart-uuid

    {
      "customer": { "email": "john@example.com", "firstName": "John", "lastName": "Smith" }
    }

    ```


    For logged-in customers, pass `{ "customer": { "customerId":
    "existing-customer-uuid" } }`.


    ### Step 5: Checkout Questions (Optional)


    If the store has checkout questions configured:


    ```

    GET /customer/cart/checkout/questions/en

    X-Cart-Id: cart-uuid

    → Returns array of questions with types (text, select, checkbox, etc.)


    POST /customer/cart/checkout/save-answers

    X-Cart-Id: cart-uuid

    { "answers": [{ "questionId": "...", "value": "..." }] }

    ```


    ### Step 6: Submit Checkout


    ```json

    POST /customer/cart/checkout/submit

    X-Cart-Id: cart-uuid

    {}

    ```


    Response includes the created order and optionally customer auth tokens for
    auto-login.


    ---


    ## Payment Integration


    ### Available Providers


    Fetch configured payment providers for your store:


    ```

    GET /customer/payment/providers

    → [{ "name": "stripe", "displayName": "Credit Card", ... }]

    ```


    ### Stripe Integration


    1. Get Stripe publishable key from `GET /customer/payment/settings`

    2. Start checkout with `provider: "stripe"` — response includes
    `clientSecret`

    3. Use Stripe Elements / Payment Element with the `clientSecret`

    4. After Stripe confirms payment client-side, call `POST /checkout/submit`


    ### Cash / Pay at Venue


    Start checkout with `provider: "cash"`. No payment processing needed —
    submit directly.


    ### Redirect-Based Payments


    Some providers redirect the customer to an external page. The start response
    includes a `redirectUrl`. After payment, the customer is redirected back to
    your `thankYouUrl`.


    ---


    ## Store Settings


    Use `GET /customer/stores/public-settings` to retrieve store configuration
    for your template:


    - **Store name** → display in header/navbar

    - **Logo** → from `storefrontSettings`

    - **Currency** → format prices correctly (e.g., `USD`, `EUR`)

    - **Timezone** → convert availability times to/from the store's timezone

    - **Contact info** → display in footer or contact page

    - **Features** → check which features are enabled (e.g., customer portal)


    ---


    ## Rate Limiting


    Requests are rate-limited per API key:


    | Category | Limit |

    |----------|-------|

    | General | 100 requests / 60 seconds |

    | Authentication | 20 requests / 10 seconds |

    | Password reset | 5 requests / hour |

    | Registration | 10 requests / minute |


    When rate-limited, you'll receive a `429 Too Many Requests` response.


    ---


    ## Response Format


    All responses use **camelCase** property names:


    ```json

    {
      "id": "abc-123",
      "title": "Haircut",
      "maxAttendees": 1,
      "duration": 3600,
      "staffMembers": [
        { "id": "staff-1", "firstName": "John", "lastName": "Doe" }
      ]
    }

    ```


    ### Pagination


    List endpoints return paginated collections:


    ```json

    {
      "data": [ ... ],
      "meta": {
        "total": 42,
        "page": 1,
        "limit": 10,
        "totalPages": 5
      }
    }

    ```


    Use `?page=2&limit=20` query parameters to paginate.


    ---


    ## Error Responses


    ```json

    {
      "statusCode": 400,
      "message": "Validation failed",
      "errors": [
        { "property": "email", "messages": ["Email is required"] }
      ]
    }

    ```


    | Status | Meaning |

    |--------|---------|

    | 400 | Validation error |

    | 401 | Invalid or missing API key / customer token |

    | 404 | Resource not found |

    | 429 | Rate limit exceeded |


    ---


    ## Timezone Handling


    - All date/time values in API requests and responses are in **UTC**

    - Pass the `timezone` query parameter to availability endpoints to get slots
    converted to a specific timezone

    - Use the store's timezone from public settings as the default display
    timezone

    - Convert user-selected times to UTC before creating appointments


    ---


    ## Webhooks (Coming Soon)


    Webhook support for real-time notifications is planned. Events will include:


    - `product.created`, `product.updated`, `product.deleted`

    - `staff_member.created`, `staff_member.updated`, `staff_member.deleted`

    - `location.created`, `location.updated`, `location.deleted`

    - `store.settings_updated`

    - `collection.updated`


    Use webhooks to invalidate cached data in your deployed storefronts.
  version: '1.0'
  contact: {}
servers:
  - url: https://api.opencals.com
security:
  - Storefront API key: []
tags: []
paths:
  /storefront/appointments/{appointmentId}:
    get:
      tags:
        - Appointments
      summary: Get appointment by ID
      description: Returns a single appointment by ID for the authenticated customer
      operationId: appointment_find
      parameters:
        - name: appointmentId
          required: true
          in: path
          description: Appointment unique identifier
          schema:
            example: 123e4567-e89b-12d3-a456-426614174000
            type: string
      responses:
        '200':
          description: The appointment details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppointmentDetailResponse'
      security:
        - bearer: []
components:
  schemas:
    AppointmentDetailResponse:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the appointment
          example: 123e4567-e89b-12d3-a456-426614174000
        name:
          type: string
          description: >-
            Generated appointment name for the user (starts at 1001 and
            increments)
          example: '1001'
        productId:
          type: string
          description: ID of the service/product for this appointment
          example: 123e4567-e89b-12d3-a456-426614174001
        staffMemberId:
          type: string
          description: ID of the staff member assigned to this appointment (if any)
          example: 123e4567-e89b-12d3-a456-426614174002
          nullable: true
        locationId:
          type: string
          description: ID of the location where the appointment will take place (if any)
          example: 123e4567-e89b-12d3-a456-426614174003
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns this appointment
          example: 123e4567-e89b-12d3-a456-426614174004
        customerId:
          type: string
          description: ID of the customer who booked the appointment
          example: 123e4567-e89b-12d3-a456-426614174005
          nullable: true
        externalOrderId:
          type: string
          description: External order ID from user's platform (if any)
          example: '12345678'
          nullable: true
        externalOrderName:
          type: string
          description: External order name/reference from user's platform
          example: '#1001'
          nullable: true
        from:
          format: date-time
          type: string
          description: Start date and time of the appointment (UTC timezone)
          example: '2023-06-15T09:00:00Z'
        to:
          format: date-time
          type: string
          description: End date and time of the appointment (UTC timezone)
          example: '2023-06-15T10:00:00Z'
        addressLine1:
          type: string
          description: First line of the appointment address
          example: 123 Main Street
          nullable: true
        addressLine2:
          type: string
          description: Second line of the appointment address
          example: Suite 456
          nullable: true
        city:
          type: string
          description: City of the appointment location
          example: New York
          nullable: true
        state:
          type: string
          description: State/province of the appointment location
          example: NY
          nullable: true
        postalCode:
          type: string
          description: Postal/zip code of the appointment location
          example: '10001'
          nullable: true
        country:
          type: string
          description: Country of the appointment location
          example: USA
          nullable: true
        status:
          $ref: '#/components/schemas/AppointmentStatusType'
          example: scheduled
        internalNote:
          type: string
          description: Internal notes about the appointment (not visible to customers)
          example: Customer requested extra attention for specific needs
          nullable: true
        createdBy:
          $ref: '#/components/schemas/AppointmentCreatedByEnum'
          example: customer
        reminderSentAt:
          format: date-time
          type: string
          description: Date and time when reminder was sent to the customer
          example: '2023-06-14T09:00:00Z'
          nullable: true
        numberOfAttendees:
          type: number
          description: Number of people attending the appointment
          example: 1
          default: 1
        createdAt:
          format: date-time
          type: string
          description: Date and time when the appointment was created
          example: '2023-06-01T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when the appointment was last updated
          example: '2023-06-02T14:15:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the appointment was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        product:
          description: Service/product details for this appointment
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailProduct'
        staffMember:
          description: Staff member assigned to this appointment
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailStaffMember'
        location:
          description: Location where the appointment will take place
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailLocation'
        customer:
          description: Customer who booked the appointment
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailCustomer'
        addOns:
          description: Add-ons attached to this appointment
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailAddOn'
        guests:
          description: Guests invited to this appointment (copied on notifications)
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailGuest'
        feedbackQuestionAnswers:
          description: Answers to feedback questions provided after the appointment
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailFeedbackAnswer'
        checkoutQuestionAnswers:
          description: Answers to checkout questions provided when booking
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailCheckoutAnswer'
        orderLineItem:
          description: The order line item linking this appointment to its order
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrderLineItem'
        order:
          description: The order associated with this appointment (via the order line item)
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrder'
      required:
        - id
        - name
        - productId
        - staffMemberId
        - locationId
        - storeId
        - customerId
        - externalOrderId
        - externalOrderName
        - from
        - to
        - addressLine1
        - addressLine2
        - city
        - state
        - postalCode
        - country
        - status
        - internalNote
        - createdBy
        - reminderSentAt
        - numberOfAttendees
        - createdAt
        - updatedAt
        - deletedAt
        - product
        - staffMember
        - location
        - customer
        - addOns
        - guests
        - feedbackQuestionAnswers
        - checkoutQuestionAnswers
        - orderLineItem
        - order
    AppointmentStatusType:
      type: string
      description: Current status of the appointment
      default: pending
      enum:
        - pending
        - scheduled
        - completed
        - canceled
    AppointmentCreatedByEnum:
      type: string
      description: Indicates who created the appointment (customer or merchant)
      default: customer
      enum:
        - customer
        - merchant
    AppointmentDetailProduct:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the product
          example: 123e4567-e89b-12d3-a456-426614174000
        productId:
          type: string
          description: ID of the product
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: External platform product ID (e.g. Shopify Product ID)
          example: '1234567890'
        externalVariantId:
          type: string
          description: External platform variant ID (e.g. Shopify Variant ID)
          example: '9876543210'
        storeId:
          type: string
          description: ID of the store that owns this product
          example: 123e4567-e89b-12d3-a456-426614174001
        slug:
          type: string
          description: URL-friendly slug for the product (unique per store)
          example: haircut-basic
        scheduleId:
          type: string
          description: ID of the schedule associated with this product
        productPoolId:
          type: string
          description: >-
            ID of the product pool this product belongs to (controls overlap
            prevention)
          nullable: true
        title:
          type: string
          description: Title of the product
          example: Haircut Service
        variantTitle:
          type: string
          description: Title of the specific product variant
          example: Short Hair
        description:
          type: string
          description: Detailed description of the product
        imageId:
          type: string
          description: ID of the product image
        color:
          type: string
          description: Color code for displaying the product
          enum:
            - slate
            - gray
            - zinc
            - neutral
            - stone
            - red
            - orange
            - amber
            - yellow
            - lime
            - green
            - emerald
            - teal
            - cyan
            - sky
            - blue
            - indigo
            - violet
            - purple
            - fuchsia
            - pink
            - rose
          example: BLUE
          default: slate
        price:
          type: number
          description: Price of the product
          example: 250
        taxable:
          type: boolean
          description: Whether the product is taxable
          default: false
        duration:
          type: number
          description: Duration of the service in seconds
          example: 3600
        allowCustomDuration:
          type: boolean
          description: >-
            Whether customers can customize the duration by selecting multiples
            of the base service duration (e.g., if base duration is 1 day,
            customers can book 1, 2, 3+ days)
          default: false
        maxDuration:
          type: number
          description: >-
            When allow_custom_duration=true, maximum duration allowed for
            multi-duration bookings in seconds (-1 for unlimited)
          default: -1
        maxAttendees:
          type: number
          description: Maximum number of attendees allowed
          default: 1
        maxGuests:
          type: number
          description: >-
            Maximum number of guests allowed per appointment. Null means
            unlimited.
          nullable: true
        allowGuests:
          type: boolean
          description: Whether customers can invite guests to the appointment
          default: false
        allowCustomerReschedule:
          type: boolean
          description: Whether customers can reschedule their bookings
          default: false
        allowCustomerCancel:
          type: boolean
          description: Whether customers can cancel their bookings
          default: false
        rescheduleGap:
          type: number
          description: >-
            Time in seconds before appointment when rescheduling is no longer
            allowed
        cancelGap:
          type: number
          description: >-
            Time in seconds before appointment when cancellation is no longer
            allowed
        beforeGap:
          type: number
          description: Buffer time in seconds required before this service
        afterGap:
          type: number
          description: Buffer time in seconds required after this service
        fixedTimes:
          type: boolean
          description: >-
            When allow_custom_duration=true, whether appointments must start and
            end at fixed times (like fixed check-in/check-out times for
            multi-duration bookings)
          default: false
        fixedStartTime:
          type: string
          description: >-
            When allow_custom_duration=true and fixed_times=true, the fixed time
            when appointments must start (HH:MM:SS) - specified in the product's
            schedule timezone, or user settings timezone if no schedule is
            assigned
          example: '09:00:00'
        fixedEndTime:
          type: string
          description: >-
            When allow_custom_duration=true and fixed_times=true, the fixed time
            when appointments must end (HH:MM:SS) - specified in the product's
            schedule timezone, or user settings timezone if no schedule is
            assigned
          example: '17:00:00'
        advanceScheduleThreshold:
          type: number
          description: How many days in advance bookings can be made
          default: 0
        sendConfirmationEmail:
          type: boolean
          description: Whether to send confirmation emails for bookings
          default: true
        sendReminderEmail:
          type: boolean
          description: Whether to send reminder emails before appointments
          default: false
        sendFeedbackEmail:
          type: boolean
          description: Whether to send feedback request emails after appointments
          default: false
        skipCheckout:
          type: boolean
          description: >-
            Whether to skip the checkout process for this product (Shopify
            merchants only)
          default: false
        status:
          type: string
          description: Current status of the product
          enum:
            - active
            - inactive
          example: ACTIVE
          default: active
        createdAt:
          type: string
          description: Timestamp when the product was created
        updatedAt:
          type: string
          description: Timestamp when the product was last updated
        deletedAt:
          type: string
          description: Timestamp when the product was deleted (for soft deletes)
        image:
          description: Primary image of the product
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Image'
      required:
        - id
        - productId
        - externalId
        - externalVariantId
        - storeId
        - slug
        - scheduleId
        - productPoolId
        - title
        - variantTitle
        - description
        - imageId
        - color
        - price
        - taxable
        - duration
        - allowCustomDuration
        - maxDuration
        - maxAttendees
        - maxGuests
        - allowGuests
        - allowCustomerReschedule
        - allowCustomerCancel
        - rescheduleGap
        - cancelGap
        - beforeGap
        - afterGap
        - fixedTimes
        - fixedStartTime
        - fixedEndTime
        - advanceScheduleThreshold
        - sendConfirmationEmail
        - sendReminderEmail
        - sendFeedbackEmail
        - skipCheckout
        - status
        - createdAt
        - updatedAt
        - deletedAt
    AppointmentDetailStaffMember:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the staff member
          example: 123e4567-e89b-12d3-a456-426614174000
        storeId:
          type: string
          description: ID of the store that owns this staff member record
          example: 123e4567-e89b-12d3-a456-426614174111
        userId:
          type: string
          description: User ID of the staff member login identity (nullable until linked)
          example: user-uuid
        scheduleId:
          type: string
          description: >-
            ID of the schedule assigned to this staff member, defines their
            availability
          example: 123e4567-e89b-12d3-a456-426614174000
        imageId:
          type: string
          description: ID of the image associated with this staff member
          example: 123e4567-e89b-12d3-a456-426614174000
        firstName:
          type: string
          description: First name of the staff member
          example: John
        lastName:
          type: string
          description: Last name of the staff member
          example: Doe
        email:
          type: string
          description: >-
            Email address of the staff member, used for notifications and
            calendar integration
          example: john.doe@example.com
        slug:
          type: string
          description: URL-friendly slug for the staff member (unique per store)
          example: mike
        refreshToken:
          type: string
          description: Refresh token for integrations like Google Calendar
          example: abc123xyz456
        createdAt:
          type: string
          description: Date and time when the staff member was created
          example: '2025-05-01T12:00:00Z'
        updatedAt:
          type: string
          description: Date and time when the staff member was last updated
          example: '2025-05-15T14:30:00Z'
        deletedAt:
          type: string
          description: Date and time when the staff member was soft deleted
          example: '2025-06-01T09:15:00Z'
        image:
          description: Profile image of the staff member
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Image'
      required:
        - id
        - storeId
        - userId
        - scheduleId
        - imageId
        - firstName
        - lastName
        - email
        - slug
        - refreshToken
        - createdAt
        - updatedAt
        - deletedAt
    AppointmentDetailLocation:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the location
          example: 123e4567-e89b-12d3-a456-426614174000
        storeId:
          type: string
          description: ID of the store that owns this location
          example: 123e4567-e89b-12d3-a456-426614174001
        scheduleId:
          type: string
          description: ID of the schedule assigned to this location (if any)
          example: 123e4567-e89b-12d3-a456-426614174002
          nullable: true
        title:
          type: string
          description: Name of the location
          example: Main Office
          nullable: true
        description:
          type: string
          description: Description of the location
          example: Our main downtown office location with 3 treatment rooms
          nullable: true
        slug:
          type: string
          description: URL-friendly slug for the location (unique per store)
          example: new-york
        type:
          type: string
          description: Type of location
          enum:
            - physical
            - online
            - delivery
          example: physical
        link:
          type: string
          description: URL link for online locations
          example: https://zoom.us/j/123456789
          nullable: true
        addressLine1:
          type: string
          description: First line of address for physical locations
          example: 123 Main Street
          nullable: true
        addressLine2:
          type: string
          description: Second line of address for physical locations
          example: Suite 200
          nullable: true
        city:
          type: string
          description: City for physical locations
          example: San Francisco
          nullable: true
        state:
          type: string
          description: State/province for physical locations
          example: CA
          nullable: true
        postalCode:
          type: string
          description: Postal code for physical locations
          example: '94105'
          nullable: true
        country:
          type: string
          description: Country for physical locations
          example: United States
          nullable: true
        addressPlaceId:
          type: string
          description: Google Place ID for the physical address
          example: ChIJIQBpAG2ahYAR_6128GcTUEo
          nullable: true
        latitude:
          type: number
          description: Latitude in WGS84
          example: 37.4224764
          nullable: true
        longitude:
          type: number
          description: Longitude in WGS84
          example: -122.0842499
          nullable: true
        createdAt:
          type: string
          description: Date when the location was created
          example: '2023-01-20T08:30:00Z'
        updatedAt:
          type: string
          description: Date when the location was last updated
          example: '2023-02-15T14:20:00Z'
          nullable: true
        deletedAt:
          type: string
          description: Date when the location was deleted (for soft deletes)
          example: '2023-03-10T11:45:00Z'
          nullable: true
        address:
          type: string
          description: The formatted address string
          nullable: true
      required:
        - id
        - storeId
        - scheduleId
        - title
        - description
        - slug
        - type
        - link
        - addressLine1
        - addressLine2
        - city
        - state
        - postalCode
        - country
        - addressPlaceId
        - latitude
        - longitude
        - createdAt
        - updatedAt
        - deletedAt
        - address
    AppointmentDetailCustomer:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the customer
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: External customer identifier from integrated system
          example: '1234567890'
        firstName:
          type: string
          description: Customer first name
          example: John
          nullable: true
        lastName:
          type: string
          description: Customer last name
          example: Smith
          nullable: true
        email:
          type: string
          description: Customer email address
          example: john.smith@example.com
          nullable: true
        phone:
          type: string
          description: Customer phone number
          example: '+12135550123'
          nullable: true
        password:
          type: string
          description: Hashed password of the customer
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns this customer record
          example: store-uuid
        language:
          $ref: '#/components/schemas/LanguageCode'
          example: en
        refreshToken:
          type: string
          description: Customer refresh token for authentication
          example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
          nullable: true
          writeOnly: true
        createdAt:
          format: date-time
          type: string
          description: Date when the customer record was created
          example: '2023-01-15T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date when the customer record was last updated
          example: '2023-02-20T14:15:00Z'
          nullable: true
        emailVerifiedAt:
          format: date-time
          type: string
          description: Date and time when the customer verified email
          example: '2023-01-02T00:00:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the order was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        isEmailVerified:
          type: boolean
          description: Indicates whether customer email is verified
        isPasswordSet:
          type: boolean
          description: Indicates whether customer password is set
      required:
        - id
        - externalId
        - firstName
        - lastName
        - email
        - phone
        - password
        - storeId
        - language
        - refreshToken
        - createdAt
        - updatedAt
        - emailVerifiedAt
        - deletedAt
        - isEmailVerified
        - isPasswordSet
    AppointmentDetailAddOn:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier
        appointmentId:
          type: string
          description: Appointment ID
        addOnId:
          type: string
          description: Add-on ID
        quantity:
          type: number
          description: Quantity of this add-on for the appointment
          default: 1
        createdAt:
          format: date-time
          type: string
          description: Created at timestamp
        addOn:
          description: The add-on details
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailAddOnItem'
      required:
        - id
        - appointmentId
        - addOnId
        - quantity
        - createdAt
        - addOn
    AppointmentDetailGuest:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier
        appointmentId:
          type: string
          description: Appointment ID
        email:
          type: string
          description: Guest email address
        createdAt:
          format: date-time
          type: string
          description: Created at timestamp
      required:
        - id
        - appointmentId
        - email
        - createdAt
    AppointmentDetailFeedbackAnswer:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the feedback question answer
          example: 123e4567-e89b-12d3-a456-426614174000
        appointmentId:
          type: string
          description: ID of the appointment this feedback relates to
          example: 123e4567-e89b-12d3-a456-426614174001
        questionId:
          type: string
          description: ID of the feedback question (set to null if question is deleted)
          example: 123e4567-e89b-12d3-a456-426614174002
          nullable: true
        question:
          type: string
          description: The feedback question text presented to the customer
          example: How would you rate the quality of service provided?
        answer:
          type: string
          description: Customer's answer to the feedback question
          example: The service was excellent, very professional and timely.
          nullable: true
        createdAt:
          format: date-time
          type: string
          description: Date and time when this feedback was recorded
          example: '2023-06-15T14:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when this feedback was last updated
          example: '2023-06-15T15:45:00Z'
          nullable: true
        files:
          description: >-
            Files the customer uploaded for this answer (file-upload questions
            only)
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailFeedbackAnswerFile'
      required:
        - id
        - appointmentId
        - questionId
        - question
        - answer
        - createdAt
        - updatedAt
        - files
    AppointmentDetailCheckoutAnswer:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the checkout question answer
          example: 123e4567-e89b-12d3-a456-426614174000
        appointmentId:
          type: string
          description: ID of the appointment this question answer relates to
          example: 123e4567-e89b-12d3-a456-426614174001
        questionId:
          type: string
          description: ID of the checkout question (set to null if question is deleted)
          example: 123e4567-e89b-12d3-a456-426614174002
          nullable: true
        question:
          type: string
          description: The checkout question text presented to the customer
          example: >-
            Do you have any allergies or medical conditions we should know
            about?
        answer:
          type: string
          description: Customer's answer to the checkout question
          example: I have a mild allergy to latex, please use vinyl gloves.
          nullable: true
        createdAt:
          format: date-time
          type: string
          description: Date and time when this answer was recorded
          example: '2023-06-10T14:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when this answer was last updated
          example: '2023-06-10T15:45:00Z'
          nullable: true
        files:
          description: >-
            Files the customer uploaded for this answer (file-upload questions
            only)
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailCheckoutAnswerFile'
      required:
        - id
        - appointmentId
        - questionId
        - question
        - answer
        - createdAt
        - updatedAt
        - files
    AppointmentDetailOrderLineItem:
      type: object
      properties:
        orderId:
          type: string
          description: ID of the order
          example: 550e8400-e29b-41d4-a716-446655440000
          nullable: true
        appointmentId:
          type: string
          description: ID of the appointment associated with line item
          example: 550e8400-e29b-41d4-a716-446655440000
          nullable: true
        externalId:
          type: string
          description: External order line item ID from user's platform (if any)
          example: '12345678'
          nullable: true
        originalUnitPrice:
          type: number
          description: Original price of the item
          example: 249.99
        discountedUnitPrice:
          type: number
          description: Discounted price of the item
          example: 249.99
        unitTaxAmount:
          type: number
          description: >-
            Tax amount applied to the item. It can be included in the original
            price or discounted price if the taxes are included in the order
            subtotal.
          example: 0
        quantity:
          type: number
          description: Quantity of the item ordered
          example: 1
        createdAt:
          format: date-time
          type: string
          description: Date and time when the order was created
          example: '2023-06-01T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when the order was last updated
          example: '2023-06-02T14:15:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the order was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        addOnSubtotal:
          type: number
          description: Subtotal of the add-ons attached to this line item
        addOnTotalTax:
          type: number
          description: Total tax of the add-ons attached to this line item
        subtotal:
          type: number
          description: The total amount of the line item
          example: 249.99
        total:
          type: number
          description: The total amount of the line item
          example: 249.99
        totalTax:
          type: number
          description: The total amount of the line item
          example: 249.99
        refundedQuantity:
          type: number
          description: The quantity of the line item that has been refunded
          example: 249.99
        refundableQuantity:
          type: number
          description: The quantity of the line item that can be refunded
          example: 249.99
        order:
          description: The order this line item belongs to
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrder'
      required:
        - orderId
        - appointmentId
        - externalId
        - originalUnitPrice
        - discountedUnitPrice
        - unitTaxAmount
        - quantity
        - createdAt
        - updatedAt
        - deletedAt
        - addOnSubtotal
        - addOnTotalTax
        - subtotal
        - total
        - totalTax
        - refundedQuantity
        - refundableQuantity
        - order
    AppointmentDetailOrder:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the order
        paymentCurrencyCode:
          type: string
          description: The currency used by the customer when placing the order.
          example: 123e4567-e89b-12d3-a456-426614174000
        taxesIncluded:
          type: boolean
          description: Whether the taxes are included in the order subtotal.
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: External order ID from user's platform (if any)
          example: shop123_order_456
          nullable: true
        externalName:
          type: string
          description: External order name/reference from user's platform
          example: '#1001'
          nullable: true
        name:
          type: string
          description: Generated order name for the user (starts at 1001 and increments)
          example: '1001'
        customerId:
          type: string
          description: ID of the customer who placed the order
          example: 123e4567-e89b-12d3-a456-426614174000
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns the order
          example: store-uuid
          nullable: true
        cartId:
          type: string
          description: ID of the cart from which the order was created
          example: 123e4567-e89b-12d3-a456-426614174000
          nullable: true
        gclid:
          type: string
          description: Google Ads click ID captured at the time of booking
          example: EAIaIQobChMI...
          nullable: true
        createdAt:
          format: date-time
          type: string
          description: Date and time when the order was created
          example: '2023-06-01T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when the order was last updated
          example: '2023-06-02T14:15:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the order was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        subtotal:
          type: number
          description: Subtotal amount of the order, excluding canceled appointments
          example: 249.99
        total:
          type: number
          description: Total amount of the order, including canceled appointments and taxes
          example: 249.99
        totalTax:
          type: number
          description: Total tax amount of the order, excluding canceled appointments
          example: 249.99
        dueToPay:
          type: number
          description: >-
            Total amount still due to be paid for the order. Derived from the
            current total (which excludes canceled appointments and reflects
            current add-ons and discounts) minus the net amount already held
            (paid minus refunded). Never negative — when the customer has
            overpaid the current total, the surplus surfaces via dueToRefund
            instead.
          example: 249.99
        paidTotal:
          type: number
          description: Total amount paid for the order
          example: 249.99
        refundedTotal:
          type: number
          description: Total amount refunded for the order
          example: 249.99
        balance:
          type: number
          description: Balance of the order; based on paid and refunded amounts
          example: 249.99
        dueToRefund:
          type: number
          description: >-
            Total amount owed back to the customer. Derived from the net amount
            held (paid minus refunded) minus the current total. Any change that
            lowers the current total below what the customer has already paid —
            a canceled appointment, a removed or reduced add-on, or a discount
            that is restored on reevaluation — surfaces the surplus here. Never
            negative.
          example: 249.99
        isFullyPaid:
          type: boolean
          description: Whether the order is fully paid
          example: false
        isFullyRefunded:
          type: boolean
          description: >-
            Whether everything the customer paid has been refunded (paid
            something, nothing held).
          example: false
        paymentStatus:
          type: string
          description: Payment status of the order
          example: paid
          enum:
            - unpaid
            - paid
            - partially-paid
        refundStatus:
          type: string
          description: Refund status of the order
          example: partially-refunded
          enum:
            - refund-owed
            - partially-refunded
            - fully-refunded
            - unrefunded
        fulfillmentStatus:
          type: string
          description: Fulfillment status of the order
          example: partially-fulfilled
          enum:
            - partially-fulfilled
            - fulfilled
            - unfulfilled
        transactions:
          description: Transactions associated with this order
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailOrderTransaction'
        lineItems:
          description: Line items in the order
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailOrderItem'
      required:
        - id
        - paymentCurrencyCode
        - taxesIncluded
        - externalId
        - externalName
        - name
        - customerId
        - storeId
        - cartId
        - createdAt
        - updatedAt
        - deletedAt
        - subtotal
        - total
        - totalTax
        - dueToPay
        - paidTotal
        - refundedTotal
        - balance
        - dueToRefund
        - isFullyPaid
        - isFullyRefunded
        - paymentStatus
        - refundStatus
        - fulfillmentStatus
        - transactions
        - lineItems
    Image:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: External identifier for the image (e.g., from storage provider)
          example: img_123456
          nullable: true
        url:
          type: string
          description: URL where the image can be accessed
          example: https://storage.example.com/images/product-image.jpg
        filename:
          type: string
          description: Original filename of the uploaded image
          example: product-image.jpg
          nullable: true
        mime:
          type: string
          description: MIME type of the image
          example: image/jpeg
          nullable: true
        createdAt:
          format: date-time
          type: string
          description: Creation timestamp
          example: '2023-01-01T12:00:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Last update timestamp
          example: '2023-01-02T12:00:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Soft deletion timestamp
          example: '2023-01-03T12:00:00Z'
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns this image
          example: store-uuid
          nullable: true
      required:
        - id
        - externalId
        - url
        - filename
        - mime
        - createdAt
        - updatedAt
        - deletedAt
        - storeId
    LanguageCode:
      type: string
      description: Language code for this translation
      enum:
        - af
        - ak
        - am
        - ar
        - as
        - az
        - be
        - bg
        - bm
        - bn
        - bo
        - br
        - bs
        - ca
        - ce
        - cs
        - cu
        - cy
        - da
        - de
        - dz
        - ee
        - el
        - en
        - eo
        - es
        - et
        - eu
        - fa
        - ff
        - fi
        - fo
        - fr
        - fy
        - ga
        - gd
        - gl
        - gu
        - gv
        - ha
        - he
        - hi
        - hr
        - hu
        - hy
        - ia
        - id
        - ig
        - ii
        - is
        - it
        - ja
        - jv
        - ka
        - ki
        - kk
        - kl
        - km
        - kn
        - ko
        - ks
        - ku
        - kw
        - ky
        - lb
        - lg
        - ln
        - lo
        - lt
        - lu
        - lv
        - mg
        - mi
        - mk
        - ml
        - mn
        - mr
        - ms
        - mt
        - my
        - nb
        - nd
        - ne
        - nl
        - nn
        - 'no'
        - om
        - or
        - os
        - pa
        - pl
        - ps
        - pt
        - pt_br
        - pt_pt
        - qu
        - rm
        - rn
        - ro
        - ru
        - rw
        - sd
        - se
        - sg
        - si
        - sk
        - sl
        - sn
        - so
        - sq
        - sr
        - su
        - sv
        - sw
        - ta
        - te
        - tg
        - th
        - ti
        - tk
        - to
        - tr
        - tt
        - ug
        - uk
        - ur
        - uz
        - vi
        - vo
        - wo
        - xh
        - yi
        - yo
        - zh
        - zh_cn
        - zh_tw
        - zu
    AppointmentDetailAddOnItem:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the add-on
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: >-
            External platform product ID (e.g. Shopify Product ID) for synced
            add-ons
          example: '1234567890'
        externalVariantId:
          type: string
          description: >-
            External platform variant ID (e.g. Shopify Variant ID) for synced
            add-ons
          example: '9876543210'
        storeId:
          type: string
          description: ID of the store that owns this add-on
          example: 123e4567-e89b-12d3-a456-426614174001
        slug:
          type: string
          description: URL-friendly slug for the add-on (unique per store)
          example: child-seat
        title:
          type: string
          description: Title of the add-on
          example: Child Seat
        description:
          type: string
          description: Detailed description of the add-on
        imageId:
          type: string
          description: ID of the primary image for the add-on
        color:
          type: string
          description: Color code used when displaying the add-on
          enum:
            - slate
            - gray
            - zinc
            - neutral
            - stone
            - red
            - orange
            - amber
            - yellow
            - lime
            - green
            - emerald
            - teal
            - cyan
            - sky
            - blue
            - indigo
            - violet
            - purple
            - fuchsia
            - pink
            - rose
          example: slate
          default: slate
        price:
          type: number
          description: Unit price of the add-on
          example: 15
        taxable:
          type: boolean
          description: Whether the add-on is taxable
          default: true
        durationMultiplied:
          type: boolean
          description: >-
            When true, the add-on is charged per base-duration unit of the
            parent appointment. Quantity on the cart/order line item mirrors the
            parent CartItem.quantity (i.e., the booked duration units). Only
            meaningful for attached products with allowCustomDuration=true.
          default: false
        maxQuantity:
          type: number
          description: >-
            Maximum quantity a customer can pick for this add-on. Only applies
            to fixed add-ons (durationMultiplied=false). Null means unlimited.
          example: 4
          minimum: 1
          nullable: true
        status:
          type: string
          description: Current status of the add-on
          enum:
            - active
            - inactive
          example: active
          default: active
        createdAt:
          type: string
          description: Timestamp when the add-on was created
        updatedAt:
          type: string
          description: Timestamp when the add-on was last updated
        deletedAt:
          type: string
          description: Timestamp when the add-on was soft-deleted
        image:
          description: Primary image of the add-on
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Image'
      required:
        - id
        - externalId
        - externalVariantId
        - storeId
        - slug
        - title
        - description
        - imageId
        - color
        - price
        - taxable
        - durationMultiplied
        - maxQuantity
        - status
        - createdAt
        - updatedAt
        - deletedAt
    AppointmentDetailFeedbackAnswerFile:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: S3 object key
          example: customer-uploads/store-id/uuid-logo.png
          nullable: true
        url:
          type: string
          description: Stored URL (informational; re-signed on read)
          nullable: true
        filename:
          type: string
          description: Original filename
          example: logo.png
          nullable: true
        mime:
          type: string
          description: MIME type
          example: image/png
          nullable: true
        size:
          type: number
          description: File size in bytes
          example: 20480
          nullable: true
        answerId:
          type: string
          description: ID of the feedback-question answer this file belongs to
          nullable: true
        createdAt:
          format: date-time
          type: string
          description: Creation timestamp
          example: '2023-01-01T12:00:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Last update timestamp
          example: '2023-01-02T12:00:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Soft deletion timestamp
          example: '2023-01-03T12:00:00Z'
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns this file
          example: store-uuid
          nullable: true
      required:
        - id
        - externalId
        - url
        - filename
        - mime
        - size
        - createdAt
        - updatedAt
        - deletedAt
        - storeId
    AppointmentDetailCheckoutAnswerFile:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: S3 object key
          example: customer-uploads/store-id/uuid-logo.png
          nullable: true
        url:
          type: string
          description: Stored URL (informational; re-signed on read)
          nullable: true
        filename:
          type: string
          description: Original filename
          example: logo.png
          nullable: true
        mime:
          type: string
          description: MIME type
          example: image/png
          nullable: true
        size:
          type: number
          description: File size in bytes
          example: 20480
          nullable: true
        answerId:
          type: string
          description: ID of the checkout-question answer this file belongs to
          nullable: true
        createdAt:
          format: date-time
          type: string
          description: Creation timestamp
          example: '2023-01-01T12:00:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Last update timestamp
          example: '2023-01-02T12:00:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Soft deletion timestamp
          example: '2023-01-03T12:00:00Z'
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns this file
          example: store-uuid
          nullable: true
      required:
        - id
        - externalId
        - url
        - filename
        - mime
        - size
        - createdAt
        - updatedAt
        - deletedAt
        - storeId
    AppointmentDetailOrderTransaction:
      type: object
      properties:
        orderId:
          type: string
          description: ID of the order
          example: 550e8400-e29b-41d4-a716-446655440000
          nullable: true
        externalId:
          type: string
          description: External order transaction ID from user's platform (if any)
          example: '12345678'
          nullable: true
        parentId:
          type: string
          description: The parent transaction ID
          example: '12345678'
          nullable: true
        refundId:
          type: string
          description: The refund ID this transaction belongs to (if any)
          example: 550e8400-e29b-41d4-a716-446655440000
          nullable: true
        type:
          type: string
          description: The type of transaction
          example: sale
          enum:
            - authorization
            - capture
            - void
            - sale
            - refund
        amount:
          type: number
          description: Amount of the transaction
          example: 249.99
        currencyCode:
          type: string
          description: The currency code
          example: USD
        gateway:
          type: string
          description: The payment gateway
          example: shopify
          enum:
            - shopify
            - cash
            - bank_transfer
            - stripe
          deprecated: true
        provider:
          type: string
          description: The payment provider (replaces gateway)
          example: stripe
          enum:
            - stripe
            - cash
            - bank_transfer
            - shopify
        status:
          type: string
          description: The status of the transaction
          example: success
          enum:
            - pending
            - success
            - failed
        createdAt:
          format: date-time
          type: string
          description: Date and time when the transaction was created
          example: '2023-06-01T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when the transaction was last updated
          example: '2023-06-02T14:15:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the transaction was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        refundableAmount:
          type: number
          description: The refundable amount for this transaction
          example: 249.99
        refundedAmount:
          type: number
          description: The refunded amount for this transaction
          example: 249.99
        isRefundable:
          type: boolean
          description: Whether this transaction is refundable
          example: true
      required:
        - orderId
        - externalId
        - parentId
        - refundId
        - type
        - amount
        - currencyCode
        - gateway
        - provider
        - status
        - createdAt
        - updatedAt
        - deletedAt
        - refundableAmount
        - refundedAmount
        - isRefundable
    AppointmentDetailOrderItem:
      type: object
      properties:
        orderId:
          type: string
          description: ID of the order
          example: 550e8400-e29b-41d4-a716-446655440000
          nullable: true
        appointmentId:
          type: string
          description: ID of the appointment associated with line item
          example: 550e8400-e29b-41d4-a716-446655440000
          nullable: true
        externalId:
          type: string
          description: External order line item ID from user's platform (if any)
          example: '12345678'
          nullable: true
        originalUnitPrice:
          type: number
          description: Original price of the item
          example: 249.99
        discountedUnitPrice:
          type: number
          description: Discounted price of the item
          example: 249.99
        unitTaxAmount:
          type: number
          description: >-
            Tax amount applied to the item. It can be included in the original
            price or discounted price if the taxes are included in the order
            subtotal.
          example: 0
        quantity:
          type: number
          description: Quantity of the item ordered
          example: 1
        createdAt:
          format: date-time
          type: string
          description: Date and time when the order was created
          example: '2023-06-01T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when the order was last updated
          example: '2023-06-02T14:15:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the order was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        addOnSubtotal:
          type: number
          description: Subtotal of the add-ons attached to this line item
        addOnTotalTax:
          type: number
          description: Total tax of the add-ons attached to this line item
        subtotal:
          type: number
          description: The total amount of the line item
          example: 249.99
        total:
          type: number
          description: The total amount of the line item
          example: 249.99
        totalTax:
          type: number
          description: The total amount of the line item
          example: 249.99
        refundedQuantity:
          type: number
          description: The quantity of the line item that has been refunded
          example: 249.99
        refundableQuantity:
          type: number
          description: The quantity of the line item that can be refunded
          example: 249.99
        appointment:
          description: The appointment this line item is for
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrderItemAppointment'
        addOnLineItems:
          description: Add-on line items attached to this line item
          type: array
          items:
            $ref: '#/components/schemas/AppointmentDetailOrderItemAddOn'
      required:
        - orderId
        - appointmentId
        - externalId
        - originalUnitPrice
        - discountedUnitPrice
        - unitTaxAmount
        - quantity
        - createdAt
        - updatedAt
        - deletedAt
        - addOnSubtotal
        - addOnTotalTax
        - subtotal
        - total
        - totalTax
        - refundedQuantity
        - refundableQuantity
        - appointment
        - addOnLineItems
    AppointmentDetailOrderItemAppointment:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the appointment
          example: 123e4567-e89b-12d3-a456-426614174000
        name:
          type: string
          description: >-
            Generated appointment name for the user (starts at 1001 and
            increments)
          example: '1001'
        productId:
          type: string
          description: ID of the service/product for this appointment
          example: 123e4567-e89b-12d3-a456-426614174001
        staffMemberId:
          type: string
          description: ID of the staff member assigned to this appointment (if any)
          example: 123e4567-e89b-12d3-a456-426614174002
          nullable: true
        locationId:
          type: string
          description: ID of the location where the appointment will take place (if any)
          example: 123e4567-e89b-12d3-a456-426614174003
          nullable: true
        storeId:
          type: string
          description: ID of the store that owns this appointment
          example: 123e4567-e89b-12d3-a456-426614174004
        customerId:
          type: string
          description: ID of the customer who booked the appointment
          example: 123e4567-e89b-12d3-a456-426614174005
          nullable: true
        externalOrderId:
          type: string
          description: External order ID from user's platform (if any)
          example: '12345678'
          nullable: true
        externalOrderName:
          type: string
          description: External order name/reference from user's platform
          example: '#1001'
          nullable: true
        from:
          format: date-time
          type: string
          description: Start date and time of the appointment (UTC timezone)
          example: '2023-06-15T09:00:00Z'
        to:
          format: date-time
          type: string
          description: End date and time of the appointment (UTC timezone)
          example: '2023-06-15T10:00:00Z'
        addressLine1:
          type: string
          description: First line of the appointment address
          example: 123 Main Street
          nullable: true
        addressLine2:
          type: string
          description: Second line of the appointment address
          example: Suite 456
          nullable: true
        city:
          type: string
          description: City of the appointment location
          example: New York
          nullable: true
        state:
          type: string
          description: State/province of the appointment location
          example: NY
          nullable: true
        postalCode:
          type: string
          description: Postal/zip code of the appointment location
          example: '10001'
          nullable: true
        country:
          type: string
          description: Country of the appointment location
          example: USA
          nullable: true
        status:
          $ref: '#/components/schemas/AppointmentStatusType'
          example: scheduled
        internalNote:
          type: string
          description: Internal notes about the appointment (not visible to customers)
          example: Customer requested extra attention for specific needs
          nullable: true
        createdBy:
          $ref: '#/components/schemas/AppointmentCreatedByEnum'
          example: customer
        reminderSentAt:
          format: date-time
          type: string
          description: Date and time when reminder was sent to the customer
          example: '2023-06-14T09:00:00Z'
          nullable: true
        numberOfAttendees:
          type: number
          description: Number of people attending the appointment
          example: 1
          default: 1
        createdAt:
          format: date-time
          type: string
          description: Date and time when the appointment was created
          example: '2023-06-01T10:30:00Z'
        updatedAt:
          format: date-time
          type: string
          description: Date and time when the appointment was last updated
          example: '2023-06-02T14:15:00Z'
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Date and time when the appointment was soft-deleted
          example: '2023-06-03T09:45:00Z'
          nullable: true
        product:
          description: Service/product for this line item
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrderItemProduct'
        staffMember:
          description: Staff member for this line item
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrderItemStaffMember'
        location:
          description: Location for this line item
          nullable: true
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrderItemLocation'
      required:
        - id
        - name
        - productId
        - staffMemberId
        - locationId
        - storeId
        - customerId
        - externalOrderId
        - externalOrderName
        - from
        - to
        - addressLine1
        - addressLine2
        - city
        - state
        - postalCode
        - country
        - status
        - internalNote
        - createdBy
        - reminderSentAt
        - numberOfAttendees
        - createdAt
        - updatedAt
        - deletedAt
        - product
        - staffMember
        - location
    AppointmentDetailOrderItemAddOn:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the order add-on line item
        orderId:
          type: string
          description: ID of the order
        lineItemId:
          type: string
          description: >-
            ID of the parent order line item (the appointment) this add-on
            belongs to
        addOnId:
          type: string
          description: ID of the add-on
        externalId:
          type: string
          description: >-
            External line item ID from the platform (e.g., Shopify) for this
            add-on
          nullable: true
        originalUnitPrice:
          type: number
          description: Original unit price
        discountedUnitPrice:
          type: number
          description: Discounted unit price
        unitTaxAmount:
          type: number
          description: Unit tax amount
        quantity:
          type: number
          description: >-
            Quantity. For fixed add-ons this is the customer-picked count; for
            duration-multiplied add-ons it is the number of base-duration units
            of the parent appointment, snapshotted at cart → order conversion.
        createdAt:
          format: date-time
          type: string
          description: Created at
        updatedAt:
          format: date-time
          type: string
          description: Updated at
          nullable: true
        deletedAt:
          format: date-time
          type: string
          description: Deleted at
          nullable: true
        subtotal:
          type: number
          description: Subtotal of this add-on line item
        total:
          type: number
          description: >-
            Total amount of this add-on line item (including tax when not
            included in price)
        totalTax:
          type: number
          description: Total tax for this add-on line item
        refundedQuantity:
          type: number
          description: Quantity already refunded
        refundableQuantity:
          type: number
          description: Remaining refundable quantity
        addOn:
          description: The add-on
          allOf:
            - $ref: '#/components/schemas/AppointmentDetailOrderItemAddOnItem'
      required:
        - id
        - orderId
        - lineItemId
        - addOnId
        - externalId
        - originalUnitPrice
        - discountedUnitPrice
        - unitTaxAmount
        - quantity
        - createdAt
        - updatedAt
        - deletedAt
        - subtotal
        - total
        - totalTax
        - refundedQuantity
        - refundableQuantity
        - addOn
    AppointmentDetailOrderItemProduct:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the product
          example: 123e4567-e89b-12d3-a456-426614174000
        productId:
          type: string
          description: ID of the product
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: External platform product ID (e.g. Shopify Product ID)
          example: '1234567890'
        externalVariantId:
          type: string
          description: External platform variant ID (e.g. Shopify Variant ID)
          example: '9876543210'
        storeId:
          type: string
          description: ID of the store that owns this product
          example: 123e4567-e89b-12d3-a456-426614174001
        slug:
          type: string
          description: URL-friendly slug for the product (unique per store)
          example: haircut-basic
        scheduleId:
          type: string
          description: ID of the schedule associated with this product
        productPoolId:
          type: string
          description: >-
            ID of the product pool this product belongs to (controls overlap
            prevention)
          nullable: true
        title:
          type: string
          description: Title of the product
          example: Haircut Service
        variantTitle:
          type: string
          description: Title of the specific product variant
          example: Short Hair
        description:
          type: string
          description: Detailed description of the product
        imageId:
          type: string
          description: ID of the product image
        color:
          type: string
          description: Color code for displaying the product
          enum:
            - slate
            - gray
            - zinc
            - neutral
            - stone
            - red
            - orange
            - amber
            - yellow
            - lime
            - green
            - emerald
            - teal
            - cyan
            - sky
            - blue
            - indigo
            - violet
            - purple
            - fuchsia
            - pink
            - rose
          example: BLUE
          default: slate
        price:
          type: number
          description: Price of the product
          example: 250
        taxable:
          type: boolean
          description: Whether the product is taxable
          default: false
        duration:
          type: number
          description: Duration of the service in seconds
          example: 3600
        allowCustomDuration:
          type: boolean
          description: >-
            Whether customers can customize the duration by selecting multiples
            of the base service duration (e.g., if base duration is 1 day,
            customers can book 1, 2, 3+ days)
          default: false
        maxDuration:
          type: number
          description: >-
            When allow_custom_duration=true, maximum duration allowed for
            multi-duration bookings in seconds (-1 for unlimited)
          default: -1
        maxAttendees:
          type: number
          description: Maximum number of attendees allowed
          default: 1
        maxGuests:
          type: number
          description: >-
            Maximum number of guests allowed per appointment. Null means
            unlimited.
          nullable: true
        allowGuests:
          type: boolean
          description: Whether customers can invite guests to the appointment
          default: false
        allowCustomerReschedule:
          type: boolean
          description: Whether customers can reschedule their bookings
          default: false
        allowCustomerCancel:
          type: boolean
          description: Whether customers can cancel their bookings
          default: false
        rescheduleGap:
          type: number
          description: >-
            Time in seconds before appointment when rescheduling is no longer
            allowed
        cancelGap:
          type: number
          description: >-
            Time in seconds before appointment when cancellation is no longer
            allowed
        beforeGap:
          type: number
          description: Buffer time in seconds required before this service
        afterGap:
          type: number
          description: Buffer time in seconds required after this service
        fixedTimes:
          type: boolean
          description: >-
            When allow_custom_duration=true, whether appointments must start and
            end at fixed times (like fixed check-in/check-out times for
            multi-duration bookings)
          default: false
        fixedStartTime:
          type: string
          description: >-
            When allow_custom_duration=true and fixed_times=true, the fixed time
            when appointments must start (HH:MM:SS) - specified in the product's
            schedule timezone, or user settings timezone if no schedule is
            assigned
          example: '09:00:00'
        fixedEndTime:
          type: string
          description: >-
            When allow_custom_duration=true and fixed_times=true, the fixed time
            when appointments must end (HH:MM:SS) - specified in the product's
            schedule timezone, or user settings timezone if no schedule is
            assigned
          example: '17:00:00'
        advanceScheduleThreshold:
          type: number
          description: How many days in advance bookings can be made
          default: 0
        sendConfirmationEmail:
          type: boolean
          description: Whether to send confirmation emails for bookings
          default: true
        sendReminderEmail:
          type: boolean
          description: Whether to send reminder emails before appointments
          default: false
        sendFeedbackEmail:
          type: boolean
          description: Whether to send feedback request emails after appointments
          default: false
        skipCheckout:
          type: boolean
          description: >-
            Whether to skip the checkout process for this product (Shopify
            merchants only)
          default: false
        status:
          type: string
          description: Current status of the product
          enum:
            - active
            - inactive
          example: ACTIVE
          default: active
        createdAt:
          type: string
          description: Timestamp when the product was created
        updatedAt:
          type: string
          description: Timestamp when the product was last updated
        deletedAt:
          type: string
          description: Timestamp when the product was deleted (for soft deletes)
        image:
          description: Primary image of the product
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Image'
      required:
        - id
        - productId
        - externalId
        - externalVariantId
        - storeId
        - slug
        - scheduleId
        - productPoolId
        - title
        - variantTitle
        - description
        - imageId
        - color
        - price
        - taxable
        - duration
        - allowCustomDuration
        - maxDuration
        - maxAttendees
        - maxGuests
        - allowGuests
        - allowCustomerReschedule
        - allowCustomerCancel
        - rescheduleGap
        - cancelGap
        - beforeGap
        - afterGap
        - fixedTimes
        - fixedStartTime
        - fixedEndTime
        - advanceScheduleThreshold
        - sendConfirmationEmail
        - sendReminderEmail
        - sendFeedbackEmail
        - skipCheckout
        - status
        - createdAt
        - updatedAt
        - deletedAt
    AppointmentDetailOrderItemStaffMember:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the staff member
          example: 123e4567-e89b-12d3-a456-426614174000
        storeId:
          type: string
          description: ID of the store that owns this staff member record
          example: 123e4567-e89b-12d3-a456-426614174111
        userId:
          type: string
          description: User ID of the staff member login identity (nullable until linked)
          example: user-uuid
        scheduleId:
          type: string
          description: >-
            ID of the schedule assigned to this staff member, defines their
            availability
          example: 123e4567-e89b-12d3-a456-426614174000
        imageId:
          type: string
          description: ID of the image associated with this staff member
          example: 123e4567-e89b-12d3-a456-426614174000
        firstName:
          type: string
          description: First name of the staff member
          example: John
        lastName:
          type: string
          description: Last name of the staff member
          example: Doe
        email:
          type: string
          description: >-
            Email address of the staff member, used for notifications and
            calendar integration
          example: john.doe@example.com
        slug:
          type: string
          description: URL-friendly slug for the staff member (unique per store)
          example: mike
        refreshToken:
          type: string
          description: Refresh token for integrations like Google Calendar
          example: abc123xyz456
        createdAt:
          type: string
          description: Date and time when the staff member was created
          example: '2025-05-01T12:00:00Z'
        updatedAt:
          type: string
          description: Date and time when the staff member was last updated
          example: '2025-05-15T14:30:00Z'
        deletedAt:
          type: string
          description: Date and time when the staff member was soft deleted
          example: '2025-06-01T09:15:00Z'
        image:
          description: Profile image of the staff member
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Image'
      required:
        - id
        - storeId
        - userId
        - scheduleId
        - imageId
        - firstName
        - lastName
        - email
        - slug
        - refreshToken
        - createdAt
        - updatedAt
        - deletedAt
    AppointmentDetailOrderItemLocation:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the location
          example: 123e4567-e89b-12d3-a456-426614174000
        storeId:
          type: string
          description: ID of the store that owns this location
          example: 123e4567-e89b-12d3-a456-426614174001
        scheduleId:
          type: string
          description: ID of the schedule assigned to this location (if any)
          example: 123e4567-e89b-12d3-a456-426614174002
          nullable: true
        title:
          type: string
          description: Name of the location
          example: Main Office
          nullable: true
        description:
          type: string
          description: Description of the location
          example: Our main downtown office location with 3 treatment rooms
          nullable: true
        slug:
          type: string
          description: URL-friendly slug for the location (unique per store)
          example: new-york
        type:
          type: string
          description: Type of location
          enum:
            - physical
            - online
            - delivery
          example: physical
        link:
          type: string
          description: URL link for online locations
          example: https://zoom.us/j/123456789
          nullable: true
        addressLine1:
          type: string
          description: First line of address for physical locations
          example: 123 Main Street
          nullable: true
        addressLine2:
          type: string
          description: Second line of address for physical locations
          example: Suite 200
          nullable: true
        city:
          type: string
          description: City for physical locations
          example: San Francisco
          nullable: true
        state:
          type: string
          description: State/province for physical locations
          example: CA
          nullable: true
        postalCode:
          type: string
          description: Postal code for physical locations
          example: '94105'
          nullable: true
        country:
          type: string
          description: Country for physical locations
          example: United States
          nullable: true
        addressPlaceId:
          type: string
          description: Google Place ID for the physical address
          example: ChIJIQBpAG2ahYAR_6128GcTUEo
          nullable: true
        latitude:
          type: number
          description: Latitude in WGS84
          example: 37.4224764
          nullable: true
        longitude:
          type: number
          description: Longitude in WGS84
          example: -122.0842499
          nullable: true
        createdAt:
          type: string
          description: Date when the location was created
          example: '2023-01-20T08:30:00Z'
        updatedAt:
          type: string
          description: Date when the location was last updated
          example: '2023-02-15T14:20:00Z'
          nullable: true
        deletedAt:
          type: string
          description: Date when the location was deleted (for soft deletes)
          example: '2023-03-10T11:45:00Z'
          nullable: true
        address:
          type: string
          description: The formatted address string
          nullable: true
      required:
        - id
        - storeId
        - scheduleId
        - title
        - description
        - slug
        - type
        - link
        - addressLine1
        - addressLine2
        - city
        - state
        - postalCode
        - country
        - addressPlaceId
        - latitude
        - longitude
        - createdAt
        - updatedAt
        - deletedAt
        - address
    AppointmentDetailOrderItemAddOnItem:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the add-on
          example: 123e4567-e89b-12d3-a456-426614174000
        externalId:
          type: string
          description: >-
            External platform product ID (e.g. Shopify Product ID) for synced
            add-ons
          example: '1234567890'
        externalVariantId:
          type: string
          description: >-
            External platform variant ID (e.g. Shopify Variant ID) for synced
            add-ons
          example: '9876543210'
        storeId:
          type: string
          description: ID of the store that owns this add-on
          example: 123e4567-e89b-12d3-a456-426614174001
        slug:
          type: string
          description: URL-friendly slug for the add-on (unique per store)
          example: child-seat
        title:
          type: string
          description: Title of the add-on
          example: Child Seat
        description:
          type: string
          description: Detailed description of the add-on
        imageId:
          type: string
          description: ID of the primary image for the add-on
        color:
          type: string
          description: Color code used when displaying the add-on
          enum:
            - slate
            - gray
            - zinc
            - neutral
            - stone
            - red
            - orange
            - amber
            - yellow
            - lime
            - green
            - emerald
            - teal
            - cyan
            - sky
            - blue
            - indigo
            - violet
            - purple
            - fuchsia
            - pink
            - rose
          example: slate
          default: slate
        price:
          type: number
          description: Unit price of the add-on
          example: 15
        taxable:
          type: boolean
          description: Whether the add-on is taxable
          default: true
        durationMultiplied:
          type: boolean
          description: >-
            When true, the add-on is charged per base-duration unit of the
            parent appointment. Quantity on the cart/order line item mirrors the
            parent CartItem.quantity (i.e., the booked duration units). Only
            meaningful for attached products with allowCustomDuration=true.
          default: false
        maxQuantity:
          type: number
          description: >-
            Maximum quantity a customer can pick for this add-on. Only applies
            to fixed add-ons (durationMultiplied=false). Null means unlimited.
          example: 4
          minimum: 1
          nullable: true
        status:
          type: string
          description: Current status of the add-on
          enum:
            - active
            - inactive
          example: active
          default: active
        createdAt:
          type: string
          description: Timestamp when the add-on was created
        updatedAt:
          type: string
          description: Timestamp when the add-on was last updated
        deletedAt:
          type: string
          description: Timestamp when the add-on was soft-deleted
        image:
          description: Primary image of the add-on
          nullable: true
          allOf:
            - $ref: '#/components/schemas/Image'
      required:
        - id
        - externalId
        - externalVariantId
        - storeId
        - slug
        - title
        - description
        - imageId
        - color
        - price
        - taxable
        - durationMultiplied
        - maxQuantity
        - status
        - createdAt
        - updatedAt
        - deletedAt
  securitySchemes:
    Storefront API key:
      type: apiKey
      in: header
      name: x-api-key
      description: Storefront API key (sfk_...)
      x-default: sfk_your_api_key

````