{
  "openapi": "3.0.3",
  "info": {
    "title": "B5N Booking API",
    "description": "API-first appointment booking system designed for service businesses. All responses include LLM-friendly `summary` fields for AI agent consumption.\n\n## Authentication\n\nAll API requests require an API key passed in the `X-API-Key` header:\n\n```\nX-API-Key: oxb_your_api_key_here\n```\n\n## Scopes\n\nAPI keys are granted specific scopes that control what operations they can perform. Available scopes:\n\n| Scope | Description |\n|-------|-------------|\n| `availability:read` | Check available appointment slots |\n| `appointments:read` | View appointment details |\n| `appointments:write` | Create and update appointments |\n| `appointments:delete` | Cancel appointments |\n| `customers:read` | View customer information |\n| `customers:write` | Create and update customers |\n| `employees:read` | View employee information |\n| `employees:write` | Manage employees |\n| `services:read` | View service types |\n| `services:write` | Manage service types |\n| `schedules:read` | View availability schedules |\n| `schedules:write` | Manage availability schedules |\n| `settings:read` | View organization settings |\n| `settings:write` | Manage organization settings |\n\n### Scope Bundles\n\nCommon scope combinations for typical use cases:\n\n- **booking_agent**: `availability:read`, `appointments:read`, `appointments:write`, `customers:read`, `customers:write`, `services:read`, `employees:read` - For AI booking agents\n- **read_only**: All `:read` scopes - For dashboards and reporting\n- **full_access**: All scopes - For admin applications\n\n## AI Agent Integration\n\nThis API is designed for LLM/AI agent tool calling. Each response includes:\n- `summary`: Human-readable description of the result\n- Structured data for programmatic access\n- Helpful error messages with hints\n\n## Rate Limiting\n\nAPI requests are rate limited to 100 requests per minute per API key.",
    "version": "1.0.0",
    "contact": {
      "name": "B5N Booking Support",
      "url": "https://oxenbooking.com"
    }
  },
  "servers": [
    {
      "url": "https://api.b5n.io",
      "description": "Production server"
    },
    {
      "url": "http://localhost:3001",
      "description": "Local development"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Availability",
      "description": "Check available appointment slots"
    },
    {
      "name": "Appointments",
      "description": "Book and manage appointments"
    },
    {
      "name": "Customers",
      "description": "Manage customer records and contact information"
    },
    {
      "name": "Employees",
      "description": "Manage bookable staff members"
    },
    {
      "name": "Locations",
      "description": "Manage business locations for multi-location support"
    },
    {
      "name": "Schedules",
      "description": "Manage employee availability rules"
    },
    {
      "name": "Blocked Dates",
      "description": "Manage holidays and time-off blocks"
    },
    {
      "name": "Services",
      "description": "Manage service types offered"
    },
    {
      "name": "Webhooks",
      "description": "Configure webhook endpoints for event notifications"
    },
    {
      "name": "API Keys",
      "description": "Manage API keys for authentication"
    },
    {
      "name": "Settings",
      "description": "Organization settings and configuration"
    },
    {
      "name": "Health",
      "description": "System health and status checks"
    },
    {
      "name": "Embed",
      "description": "Embeddable booking widget configuration"
    }
  ],
  "paths": {
    "/api/availability": {
      "get": {
        "operationId": "checkAvailability",
        "summary": "Check available appointment slots",
        "description": "Returns available time slots for a given date. Use this to find open times before booking an appointment. The response includes an LLM-friendly summary like '3 slots available on Monday: 9am with Mike, 10am with Sarah'.\n\n**Required scope:** `availability:read`",
        "tags": ["Availability"],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": true,
            "description": "Date to check availability for (YYYY-MM-DD format)",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2024-01-15"
            }
          },
          {
            "name": "service_type",
            "in": "query",
            "description": "Filter by service type slug (e.g., 'drain-cleaning')",
            "schema": {
              "type": "string",
              "example": "drain-cleaning"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "description": "Filter to a specific employee's availability",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "duration_minutes",
            "in": "query",
            "description": "Desired appointment duration in minutes (default: 60)",
            "schema": {
              "type": "integer",
              "default": 60,
              "minimum": 15,
              "maximum": 480
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Available slots found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityResponse"
                },
                "example": {
                  "available": true,
                  "date": "2024-01-15",
                  "slots": [
                    {
                      "start": "2024-01-15T09:00:00Z",
                      "end": "2024-01-15T10:00:00Z",
                      "employee": {
                        "id": "emp_abc123",
                        "name": "Mike Johnson"
                      }
                    },
                    {
                      "start": "2024-01-15T10:00:00Z",
                      "end": "2024-01-15T11:00:00Z",
                      "employee": {
                        "id": "emp_abc123",
                        "name": "Mike Johnson"
                      }
                    }
                  ],
                  "summary": "2 slots available on Monday, January 15th: 9am and 10am with Mike Johnson"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/api/appointments": {
      "get": {
        "operationId": "listAppointments",
        "summary": "List appointments",
        "description": "Retrieve a paginated list of appointments for the organization. Filter by status, employee, or date range.\n\n**Required scope:** `appointments:read`",
        "tags": ["Appointments"],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filter by appointment status",
            "schema": {
              "type": "string",
              "enum": ["scheduled", "confirmed", "completed", "cancelled", "no_show"]
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "description": "Filter by employee ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "description": "Filter appointments from this date (YYYY-MM-DD)",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "description": "Filter appointments until this date (YYYY-MM-DD)",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 50)",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Pagination offset (default: 0)",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of appointments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppointmentListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createAppointment",
        "summary": "Book a new appointment",
        "description": "Create a new appointment booking. The system will verify the time slot is available before booking. Returns a confirmation message suitable for reading to customers.\n\n**Required scope:** `appointments:write`",
        "tags": ["Appointments"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAppointmentRequest"
              },
              "example": {
                "start_time": "2024-01-15T09:00:00Z",
                "duration_minutes": 60,
                "employee_id": "emp_abc123",
                "service_type": "drain-cleaning",
                "customer_name": "John Smith",
                "customer_phone": "+15551234567",
                "customer_email": "john@example.com",
                "notes": "Please ring doorbell"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Appointment created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookingResponse"
                },
                "example": {
                  "success": true,
                  "appointment": {
                    "id": "apt_xyz789",
                    "start_time": "2024-01-15T09:00:00Z",
                    "end_time": "2024-01-15T10:00:00Z",
                    "status": "scheduled",
                    "customer_name": "John Smith"
                  },
                  "confirmation": "Appointment booked for Monday, January 15 at 9:00 AM with Mike Johnson."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "description": "Time slot no longer available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "success": false,
                  "error": "Time slot is no longer available",
                  "summary": "Sorry, that time slot has been taken. Please choose another time."
                }
              }
            }
          }
        }
      }
    },
    "/api/appointments/{id}": {
      "get": {
        "operationId": "getAppointment",
        "summary": "Get appointment details",
        "description": "Retrieve details for a specific appointment by ID.\n\n**Required scope:** `appointments:read`",
        "tags": ["Appointments"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Appointment ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Appointment details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppointmentResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateAppointment",
        "summary": "Update an appointment",
        "description": "Update appointment details such as status, time, or customer information. Can be used to confirm, reschedule, or update notes.\n\n**Required scope:** `appointments:write`",
        "tags": ["Appointments"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAppointmentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Appointment updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppointmentResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "cancelAppointment",
        "summary": "Cancel an appointment",
        "description": "Cancel an existing appointment. The appointment record is retained with status 'cancelled'.\n\n**Required scope:** `appointments:delete`",
        "tags": ["Appointments"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Appointment cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "summary": {
                      "type": "string",
                      "example": "Appointment for January 15 at 9am has been cancelled."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/appointments/lookup": {
      "get": {
        "operationId": "lookupAppointments",
        "summary": "Find appointments by phone number",
        "description": "Look up appointments for a customer using their phone number. Returns upcoming and recent appointments. Useful for AI agents helping customers check their bookings.\n\n**Required scope:** `appointments:read`",
        "tags": ["Appointments"],
        "parameters": [
          {
            "name": "phone",
            "in": "query",
            "required": true,
            "description": "Customer phone number (E.164 format recommended)",
            "schema": {
              "type": "string",
              "example": "+15551234567"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Appointments found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "appointments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Appointment"
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "summary": {
                      "type": "string",
                      "example": "Found 2 appointments for this phone number: Jan 15 at 9am (upcoming), Jan 10 at 2pm (completed)"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/customers": {
      "get": {
        "operationId": "listCustomers",
        "summary": "List customers",
        "description": "Get a paginated list of customers for the organization. Supports filtering by status, tags, and search.\n\n**Required scope:** `customers:read`",
        "tags": ["Customers"],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Page number (default: 1)",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Results per page (default: 20, max: 100)",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "active",
            "in": "query",
            "description": "Filter by active status",
            "schema": {
              "type": "string",
              "enum": ["true", "false", "all"],
              "default": "all"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search by name, email, or phone",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "tags",
            "in": "query",
            "description": "Filter by tags (comma-separated)",
            "schema": {
              "type": "string",
              "example": "vip,repeat-customer"
            }
          },
          {
            "name": "sort_by",
            "in": "query",
            "description": "Sort field",
            "schema": {
              "type": "string",
              "enum": ["name", "email", "created_at", "updated_at"],
              "default": "name"
            }
          },
          {
            "name": "sort_order",
            "in": "query",
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "enum": ["asc", "desc"],
              "default": "asc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of customers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createCustomer",
        "summary": "Create a customer",
        "description": "Add a new customer to the organization. Checks for duplicate email/phone.\n\n**Required scope:** `customers:write`",
        "tags": ["Customers"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomerRequest"
              },
              "example": {
                "name": "John Smith",
                "email": "john@example.com",
                "phone": "+15551234567",
                "address": "123 Main St",
                "city": "Austin",
                "state": "TX",
                "zip": "78701",
                "tags": ["vip"],
                "notes": "Preferred morning appointments",
                "source": "website"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Customer created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "description": "Customer with this email or phone already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Customer already exists",
                  "message": "A customer with this email already exists",
                  "existing_customer": {
                    "id": "cust_abc123",
                    "name": "John Smith"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{id}": {
      "get": {
        "operationId": "getCustomer",
        "summary": "Get customer details",
        "description": "Get detailed information about a customer including appointment stats and history.\n\n**Required scope:** `customers:read`",
        "tags": ["Customers"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Customer ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer details with stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDetailResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateCustomer",
        "summary": "Update a customer",
        "description": "Update customer information. Partial updates supported.\n\n**Required scope:** `customers:write`",
        "tags": ["Customers"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomerRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Another customer has this email or phone"
          }
        }
      },
      "delete": {
        "operationId": "archiveCustomer",
        "summary": "Archive a customer",
        "description": "Soft delete a customer by setting is_active=false. Customer data is preserved.\n\n**Required scope:** `customers:write`",
        "tags": ["Customers"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer archived",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "summary": {
                      "type": "string",
                      "example": "Archived customer \"John Smith\". Set is_active=true to restore."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/customers/{id}/message": {
      "post": {
        "operationId": "sendCustomerMessage",
        "summary": "Send message to customer",
        "description": "Send an email or SMS message to a customer. Email requires RESEND_API_KEY configuration. SMS requires Twilio configuration.\n\n**Required scope:** `customers:write`",
        "tags": ["Customers"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessageRequest"
              },
              "example": {
                "type": "email",
                "subject": "Appointment Reminder",
                "message": "Hi! This is a reminder about your upcoming appointment tomorrow at 9am."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message sent",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "type": {
                      "type": "string",
                      "enum": ["email", "sms"]
                    },
                    "recipient": {
                      "type": "string"
                    },
                    "summary": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Customer missing required contact info"
          },
          "503": {
            "description": "Messaging service not configured"
          }
        }
      }
    },
    "/api/employees": {
      "get": {
        "operationId": "listEmployees",
        "summary": "List employees",
        "description": "Get all employees (bookable staff) for the organization.\n\n**Required scope:** `employees:read`",
        "tags": ["Employees"],
        "parameters": [
          {
            "name": "active",
            "in": "query",
            "description": "Filter by active status",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of employees",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createEmployee",
        "summary": "Create an employee",
        "description": "Add a new bookable staff member to the organization.\n\n**Required scope:** `employees:write`",
        "tags": ["Employees"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEmployeeRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Employee created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/employees/{id}": {
      "get": {
        "operationId": "getEmployee",
        "summary": "Get employee details",
        "description": "Get details for a specific employee.\n\n**Required scope:** `employees:read`",
        "tags": ["Employees"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Employee details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateEmployee",
        "summary": "Update an employee",
        "description": "Update an employee's information.\n\n**Required scope:** `employees:write`",
        "tags": ["Employees"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEmployeeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Employee updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteEmployee",
        "summary": "Delete an employee",
        "description": "Remove an employee from the organization.\n\n**Required scope:** `employees:write`",
        "tags": ["Employees"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Employee deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "summary": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/locations": {
      "get": {
        "operationId": "listLocations",
        "summary": "List locations",
        "description": "Get all business locations for the organization. Returns employee and service counts per location.\n\n**Required scope:** `settings:read` or dashboard session",
        "tags": ["Locations"],
        "parameters": [
          {
            "name": "include_inactive",
            "in": "query",
            "description": "Include inactive locations (default: false)",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of locations",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createLocation",
        "summary": "Create a location",
        "description": "Add a new business location to the organization.\n\n**Required scope:** `settings:write` or dashboard session",
        "tags": ["Locations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLocationRequest"
              },
              "example": {
                "name": "Downtown Office",
                "address": "123 Main St",
                "city": "Austin",
                "state": "TX",
                "zip": "78701",
                "phone": "+15551234567",
                "timezone": "America/Chicago"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Location created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/locations/{id}": {
      "get": {
        "operationId": "getLocation",
        "summary": "Get location details",
        "description": "Get details for a specific location.\n\n**Required scope:** `settings:read` or dashboard session",
        "tags": ["Locations"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Location details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateLocation",
        "summary": "Update a location",
        "description": "Update location information.\n\n**Required scope:** `settings:write` or dashboard session",
        "tags": ["Locations"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLocationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Location updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteLocation",
        "summary": "Delete a location",
        "description": "Remove a location. Fails if employees or services are still assigned.\n\n**Required scope:** `settings:write` or dashboard session",
        "tags": ["Locations"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Location deleted"
          },
          "400": {
            "description": "Location has assigned employees or services"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/schedules": {
      "get": {
        "operationId": "listSchedules",
        "summary": "List availability rules",
        "description": "Get weekly availability rules for employees. Rules define when each employee is available for bookings.\n\n**Required scope:** `schedules:read`",
        "tags": ["Schedules"],
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "description": "Filter by employee",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of availability rules",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createSchedule",
        "summary": "Create availability rule",
        "description": "Add a new weekly availability rule for an employee.\n\n**Required scope:** `schedules:write`",
        "tags": ["Schedules"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateScheduleRequest"
              },
              "example": {
                "employee_id": "emp_abc123",
                "day_of_week": 1,
                "start_time": "09:00",
                "end_time": "17:00",
                "is_available": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Schedule rule created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/schedules/bulk": {
      "post": {
        "operationId": "bulkUpdateSchedules",
        "summary": "Bulk update availability",
        "description": "Set the entire weekly schedule for an employee in one request. Can replace all existing rules or merge with existing ones.\n\n**Required scope:** `schedules:write`",
        "tags": ["Schedules"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkScheduleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Schedule updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/schedules/{id}": {
      "get": {
        "operationId": "getSchedule",
        "summary": "Get availability rule",
        "description": "Get details for a specific availability rule.\n\n**Required scope:** `schedules:read`",
        "tags": ["Schedules"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability rule details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateSchedule",
        "summary": "Update availability rule",
        "description": "Update an employee's availability rule. Validates for time overlaps.\n\n**Required scope:** `schedules:write`",
        "tags": ["Schedules"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateScheduleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Schedule rule updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Time range overlaps with existing rule"
          }
        }
      },
      "delete": {
        "operationId": "deleteSchedule",
        "summary": "Delete availability rule",
        "description": "Remove an availability rule from an employee's schedule.\n\n**Required scope:** `schedules:write`",
        "tags": ["Schedules"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule rule deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "summary": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/blocked-dates": {
      "get": {
        "operationId": "listBlockedDates",
        "summary": "List blocked dates",
        "description": "Get blocked dates (holidays, vacations, time-off) for the organization.\n\n**Required scope:** `schedules:read`",
        "tags": ["Blocked Dates"],
        "parameters": [
          {
            "name": "date_from",
            "in": "query",
            "description": "Start date filter (YYYY-MM-DD)",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "description": "End date filter (YYYY-MM-DD)",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "description": "Filter by specific employee",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "include_org_wide",
            "in": "query",
            "description": "Include organization-wide blocks (default: true)",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of blocked dates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedDateListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createBlockedDate",
        "summary": "Create blocked date",
        "description": "Block a date or date range for an employee or the entire organization. Supports single dates or ranges.\n\n**Required scope:** `schedules:write`",
        "tags": ["Blocked Dates"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBlockedDateRequest"
              },
              "examples": {
                "single_day": {
                  "summary": "Block a single day",
                  "value": {
                    "blocked_date": "2024-01-15",
                    "all_day": true,
                    "reason": "Company Holiday"
                  }
                },
                "date_range": {
                  "summary": "Block a date range",
                  "value": {
                    "start_date": "2024-01-15",
                    "end_date": "2024-01-19",
                    "employee_id": "emp_abc123",
                    "all_day": true,
                    "reason": "Vacation"
                  }
                },
                "partial_day": {
                  "summary": "Block partial day",
                  "value": {
                    "blocked_date": "2024-01-15",
                    "all_day": false,
                    "start_time": "09:00",
                    "end_time": "12:00",
                    "reason": "Morning appointment"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Blocked date created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedDateResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict with existing block",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/blocked-dates/{id}": {
      "get": {
        "operationId": "getBlockedDate",
        "summary": "Get blocked date details",
        "description": "Get details for a specific blocked date.\n\n**Required scope:** `schedules:read`",
        "tags": ["Blocked Dates"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Blocked date details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedDateResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateBlockedDate",
        "summary": "Update blocked date",
        "description": "Update a blocked date's information.\n\n**Required scope:** `schedules:write`",
        "tags": ["Blocked Dates"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBlockedDateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Blocked date updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedDateResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteBlockedDate",
        "summary": "Delete blocked date",
        "description": "Remove a blocked date.\n\n**Required scope:** `schedules:write`",
        "tags": ["Blocked Dates"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Blocked date deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "summary": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/services": {
      "get": {
        "operationId": "listServices",
        "summary": "List service types",
        "description": "Get all service types offered by the organization.\n\n**Required scope:** `services:read`",
        "tags": ["Services"],
        "parameters": [
          {
            "name": "active",
            "in": "query",
            "description": "Filter by active status",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of services",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createService",
        "summary": "Create service type",
        "description": "Add a new service type to the organization.\n\n**Required scope:** `services:write`",
        "tags": ["Services"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateServiceRequest"
              },
              "example": {
                "name": "Drain Cleaning",
                "slug": "drain-cleaning",
                "description": "Professional drain cleaning service",
                "duration_minutes": 60,
                "price": 150.00,
                "active": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Service created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/services/{id}": {
      "get": {
        "operationId": "getService",
        "summary": "Get service details",
        "description": "Get details for a specific service type.\n\n**Required scope:** `services:read`",
        "tags": ["Services"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Service details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateService",
        "summary": "Update service type",
        "description": "Update a service type's information.\n\n**Required scope:** `services:write`",
        "tags": ["Services"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateServiceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteService",
        "summary": "Delete service type",
        "description": "Remove a service type from the organization.\n\n**Required scope:** `services:write`",
        "tags": ["Services"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Service deleted"
          }
        }
      }
    },
    "/api/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhook endpoints",
        "description": "Get all configured webhook endpoints for the organization.\n\n**Required scope:** `settings:read`",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "active_only",
            "in": "query",
            "description": "Only show active webhooks",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create webhook endpoint",
        "description": "Register a new webhook endpoint to receive event notifications.\n\n**Required scope:** `settings:write`",
        "tags": ["Webhooks"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              },
              "example": {
                "url": "https://example.com/webhook",
                "events": ["appointment.created", "appointment.cancelled"],
                "is_active": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created (secret included only in this response)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/webhooks/{id}": {
      "get": {
        "operationId": "getWebhook",
        "summary": "Get webhook details",
        "description": "Get details for a specific webhook endpoint.\n\n**Required scope:** `settings:read`",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook details (secret is masked)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateWebhook",
        "summary": "Update webhook endpoint",
        "description": "Update a webhook endpoint's configuration.\n\n**Required scope:** `settings:write`",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete webhook endpoint",
        "description": "Remove a webhook endpoint.\n\n**Required scope:** `settings:write`",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook deleted"
          }
        }
      }
    },
    "/api/webhooks/{id}/logs": {
      "get": {
        "operationId": "getWebhookLogs",
        "summary": "Get webhook delivery logs",
        "description": "View delivery attempt history for a webhook endpoint.\n\n**Required scope:** `settings:read`",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "name": "success_only",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "failed_only",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook logs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookLogsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/webhooks/{id}/test": {
      "post": {
        "operationId": "testWebhook",
        "summary": "Send test webhook",
        "description": "Send a test payload to verify the webhook endpoint is working.\n\n**Required scope:** `settings:write`",
        "tags": ["Webhooks"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Test successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "response_status": {
                      "type": "integer"
                    },
                    "response_time_ms": {
                      "type": "integer"
                    },
                    "summary": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Webhook delivery failed"
          }
        }
      }
    },
    "/api/api-keys": {
      "get": {
        "operationId": "listApiKeys",
        "summary": "List API keys",
        "description": "Get all API keys for the organization. Keys are masked - only the prefix is shown.\n\n**Requires:** Dashboard session authentication",
        "tags": ["API Keys"],
        "security": [],
        "responses": {
          "200": {
            "description": "List of API keys",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createApiKey",
        "summary": "Create an API key",
        "description": "Generate a new API key. The full key is only returned once in this response - store it securely.\n\n**Requires:** Dashboard session authentication",
        "tags": ["API Keys"],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              },
              "example": {
                "name": "Booking Agent",
                "scopes": ["availability:read", "appointments:read", "appointments:write", "services:read", "employees:read"],
                "expires_at": "2025-12-31T23:59:59Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key created (full key only shown once)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/api-keys/{id}": {
      "get": {
        "operationId": "getApiKey",
        "summary": "Get API key details",
        "description": "Get details for a specific API key (key is masked).\n\n**Requires:** Dashboard session authentication",
        "tags": ["API Keys"],
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "API key details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateApiKey",
        "summary": "Update an API key",
        "description": "Update API key name, scopes, or active status.\n\n**Requires:** Dashboard session authentication",
        "tags": ["API Keys"],
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateApiKeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key updated"
          }
        }
      },
      "delete": {
        "operationId": "deleteApiKey",
        "summary": "Revoke an API key",
        "description": "Permanently revoke an API key. This cannot be undone.\n\n**Requires:** Dashboard session authentication",
        "tags": ["API Keys"],
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "API key revoked"
          }
        }
      }
    },
    "/api/settings": {
      "get": {
        "operationId": "getSettings",
        "summary": "Get organization settings",
        "description": "Get all settings for the organization including business info, booking rules, and preferences.\n\n**Required scope:** `settings:read`",
        "tags": ["Settings"],
        "responses": {
          "200": {
            "description": "Organization settings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettingsResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateSettings",
        "summary": "Update organization settings",
        "description": "Update organization settings. Partial updates supported.\n\n**Required scope:** `settings:write`",
        "tags": ["Settings"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettingsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health check",
        "description": "Check if the API is healthy and responding. No authentication required.",
        "tags": ["Health"],
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/embed/config": {
      "get": {
        "operationId": "getEmbedConfig",
        "summary": "Get embed widget configuration",
        "description": "Returns configuration for the embeddable booking widget including organization details and available services. This is a public endpoint used by the embed widget script.\n\n**No authentication required** - but requests are validated against the organization's domain allowlist.\n\n## Domain Security\n\nOrganizations can restrict which domains are allowed to embed their booking widget:\n\n- **Public mode enabled + no domains configured**: All domains allowed\n- **Public mode enabled + domains configured**: Only those domains allowed\n- **Public mode disabled + domains configured**: Only those domains allowed\n- **Public mode disabled + no domains configured**: All domains blocked\n\nDomain patterns support:\n- Exact match: `example.com`\n- Wildcard subdomains: `*.example.com` (matches `app.example.com`, `www.example.com`)\n- Localhost with port: `localhost:3000`",
        "tags": ["Embed"],
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "Organization slug (URL-friendly identifier)",
            "schema": {
              "type": "string",
              "example": "acme-plumbing"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Embed configuration retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbedConfigResponse"
                },
                "example": {
                  "organization": {
                    "id": "org_abc123",
                    "name": "Acme Plumbing",
                    "slug": "acme-plumbing",
                    "timezone": "America/New_York",
                    "settings": {
                      "require_phone": true,
                      "require_email": false,
                      "min_notice_hours": 2,
                      "max_advance_days": 30
                    }
                  },
                  "services": [
                    {
                      "id": "svc_123",
                      "name": "Drain Cleaning",
                      "slug": "drain-cleaning",
                      "description": "Professional drain cleaning service",
                      "duration_minutes": 60,
                      "price_cents": 15000,
                      "color": "#10b981"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/DomainForbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key for authentication. Format: oxb_xxxxxxxxx"
      }
    },
    "schemas": {
      "AvailabilityResponse": {
        "type": "object",
        "properties": {
          "available": {
            "type": "boolean",
            "description": "Whether any slots are available"
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "The requested date"
          },
          "slots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimeSlot"
            }
          },
          "summary": {
            "type": "string",
            "description": "LLM-friendly description of availability"
          }
        }
      },
      "TimeSlot": {
        "type": "object",
        "properties": {
          "start": {
            "type": "string",
            "format": "date-time",
            "description": "Slot start time (ISO 8601)"
          },
          "end": {
            "type": "string",
            "format": "date-time",
            "description": "Slot end time (ISO 8601)"
          },
          "employee": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "Appointment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "start_time": {
            "type": "string",
            "format": "date-time"
          },
          "end_time": {
            "type": "string",
            "format": "date-time"
          },
          "duration_minutes": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": ["scheduled", "confirmed", "completed", "cancelled", "no_show"]
          },
          "customer_name": {
            "type": "string"
          },
          "customer_phone": {
            "type": "string"
          },
          "customer_email": {
            "type": "string"
          },
          "customer_address": {
            "type": "string"
          },
          "service_type_name": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "employee_id": {
            "type": "string",
            "format": "uuid"
          },
          "employee": {
            "$ref": "#/components/schemas/Employee"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateAppointmentRequest": {
        "type": "object",
        "required": ["start_time", "customer_name", "customer_phone"],
        "properties": {
          "start_time": {
            "type": "string",
            "format": "date-time",
            "description": "Appointment start time (ISO 8601)"
          },
          "duration_minutes": {
            "type": "integer",
            "default": 60,
            "description": "Appointment duration in minutes"
          },
          "employee_id": {
            "type": "string",
            "format": "uuid",
            "description": "Specific employee to book with"
          },
          "service_type": {
            "type": "string",
            "description": "Service type slug"
          },
          "customer_name": {
            "type": "string",
            "description": "Customer's full name"
          },
          "customer_phone": {
            "type": "string",
            "description": "Customer phone (E.164 format recommended)"
          },
          "customer_email": {
            "type": "string",
            "format": "email",
            "description": "Customer email address"
          },
          "customer_address": {
            "type": "string",
            "description": "Service address"
          },
          "notes": {
            "type": "string",
            "description": "Additional notes for the appointment"
          },
          "external_id": {
            "type": "string",
            "description": "External reference ID from your system"
          }
        }
      },
      "UpdateAppointmentRequest": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["scheduled", "confirmed", "completed", "cancelled", "no_show"]
          },
          "start_time": {
            "type": "string",
            "format": "date-time"
          },
          "duration_minutes": {
            "type": "integer"
          },
          "customer_name": {
            "type": "string"
          },
          "customer_phone": {
            "type": "string"
          },
          "customer_email": {
            "type": "string",
            "format": "email"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "BookingResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "appointment": {
            "$ref": "#/components/schemas/Appointment"
          },
          "confirmation": {
            "type": "string",
            "description": "Human-readable confirmation message"
          }
        }
      },
      "AppointmentResponse": {
        "type": "object",
        "properties": {
          "appointment": {
            "$ref": "#/components/schemas/Appointment"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "AppointmentListResponse": {
        "type": "object",
        "properties": {
          "appointments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Appointment"
            }
          },
          "count": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          }
        }
      },
      "Employee": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateEmployeeRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "active": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "UpdateEmployeeRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "EmployeeResponse": {
        "type": "object",
        "properties": {
          "employee": {
            "$ref": "#/components/schemas/Employee"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "EmployeeListResponse": {
        "type": "object",
        "properties": {
          "employees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Employee"
            }
          },
          "count": {
            "type": "integer"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "Schedule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "employee_id": {
            "type": "string",
            "format": "uuid"
          },
          "day_of_week": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6,
            "description": "0=Sunday, 1=Monday, ..., 6=Saturday"
          },
          "start_time": {
            "type": "string",
            "pattern": "^([01]?[0-9]|2[0-3]):[0-5][0-9]$",
            "example": "09:00"
          },
          "end_time": {
            "type": "string",
            "pattern": "^([01]?[0-9]|2[0-3]):[0-5][0-9]$",
            "example": "17:00"
          },
          "is_available": {
            "type": "boolean"
          }
        }
      },
      "CreateScheduleRequest": {
        "type": "object",
        "required": ["employee_id", "day_of_week", "start_time", "end_time"],
        "properties": {
          "employee_id": {
            "type": "string",
            "format": "uuid"
          },
          "day_of_week": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "start_time": {
            "type": "string",
            "example": "09:00"
          },
          "end_time": {
            "type": "string",
            "example": "17:00"
          },
          "is_available": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "BulkScheduleRequest": {
        "type": "object",
        "required": ["employee_id", "rules"],
        "properties": {
          "employee_id": {
            "type": "string",
            "format": "uuid"
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "day_of_week": {
                  "type": "integer"
                },
                "start_time": {
                  "type": "string"
                },
                "end_time": {
                  "type": "string"
                },
                "is_available": {
                  "type": "boolean"
                }
              }
            }
          }
        }
      },
      "ScheduleResponse": {
        "type": "object",
        "properties": {
          "rule": {
            "$ref": "#/components/schemas/Schedule"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "ScheduleListResponse": {
        "type": "object",
        "properties": {
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Schedule"
            }
          },
          "count": {
            "type": "integer"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "BlockedDate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "employee_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "null = organization-wide block"
          },
          "blocked_date": {
            "type": "string",
            "format": "date"
          },
          "all_day": {
            "type": "boolean"
          },
          "start_time": {
            "type": "string",
            "nullable": true
          },
          "end_time": {
            "type": "string",
            "nullable": true
          },
          "reason": {
            "type": "string"
          },
          "recurring_yearly": {
            "type": "boolean"
          }
        }
      },
      "CreateBlockedDateRequest": {
        "type": "object",
        "properties": {
          "blocked_date": {
            "type": "string",
            "format": "date",
            "description": "Single date to block"
          },
          "start_date": {
            "type": "string",
            "format": "date",
            "description": "Start of date range"
          },
          "end_date": {
            "type": "string",
            "format": "date",
            "description": "End of date range"
          },
          "employee_id": {
            "type": "string",
            "format": "uuid",
            "description": "Employee to block (null for org-wide)"
          },
          "all_day": {
            "type": "boolean",
            "default": true
          },
          "start_time": {
            "type": "string",
            "description": "Start time if not all day"
          },
          "end_time": {
            "type": "string",
            "description": "End time if not all day"
          },
          "reason": {
            "type": "string"
          },
          "recurring_yearly": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "UpdateBlockedDateRequest": {
        "type": "object",
        "properties": {
          "blocked_date": {
            "type": "string",
            "format": "date"
          },
          "all_day": {
            "type": "boolean"
          },
          "start_time": {
            "type": "string"
          },
          "end_time": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "recurring_yearly": {
            "type": "boolean"
          }
        }
      },
      "BlockedDateResponse": {
        "type": "object",
        "properties": {
          "blocked_date": {
            "$ref": "#/components/schemas/BlockedDate"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "BlockedDateListResponse": {
        "type": "object",
        "properties": {
          "blocked_dates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BlockedDate"
            }
          },
          "count": {
            "type": "integer"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "Service": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "duration_minutes": {
            "type": "integer"
          },
          "price": {
            "type": "number"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "CreateServiceRequest": {
        "type": "object",
        "required": ["name", "duration_minutes"],
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "duration_minutes": {
            "type": "integer",
            "minimum": 15
          },
          "price": {
            "type": "number",
            "minimum": 0
          },
          "active": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "UpdateServiceRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "duration_minutes": {
            "type": "integer"
          },
          "price": {
            "type": "number"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "ServiceResponse": {
        "type": "object",
        "properties": {
          "service": {
            "$ref": "#/components/schemas/Service"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "ServiceListResponse": {
        "type": "object",
        "properties": {
          "services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Service"
            }
          },
          "count": {
            "type": "integer"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "appointment.created",
                "appointment.updated",
                "appointment.cancelled",
                "appointment.confirmed",
                "appointment.completed",
                "appointment.no_show",
                "appointment.reminder"
              ]
            }
          },
          "is_active": {
            "type": "boolean"
          },
          "last_triggered_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "failure_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateWebhookRequest": {
        "type": "object",
        "required": ["url", "events"],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Webhook endpoint URL (must be HTTPS)"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "appointment.created",
                "appointment.updated",
                "appointment.cancelled",
                "appointment.confirmed",
                "appointment.completed",
                "appointment.no_show",
                "appointment.reminder"
              ]
            },
            "minItems": 1
          },
          "is_active": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "is_active": {
            "type": "boolean"
          },
          "regenerate_secret": {
            "type": "boolean",
            "description": "Set to true to regenerate the webhook secret"
          }
        }
      },
      "WebhookResponse": {
        "type": "object",
        "properties": {
          "webhook": {
            "$ref": "#/components/schemas/Webhook"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "WebhookCreateResponse": {
        "type": "object",
        "properties": {
          "webhook": {
            "$ref": "#/components/schemas/Webhook"
          },
          "secret": {
            "type": "string",
            "description": "Webhook signing secret (only shown once)"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "WebhookListResponse": {
        "type": "object",
        "properties": {
          "webhooks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "count": {
            "type": "integer"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "WebhookLogsResponse": {
        "type": "object",
        "properties": {
          "logs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "event": {
                  "type": "string"
                },
                "success": {
                  "type": "boolean"
                },
                "response_status": {
                  "type": "integer",
                  "nullable": true
                },
                "error": {
                  "type": "string",
                  "nullable": true
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "count": {
            "type": "integer"
          },
          "stats": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "successful": {
                "type": "integer"
              },
              "failed": {
                "type": "integer"
              },
              "success_rate": {
                "type": "string"
              }
            }
          }
        }
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "source": {
            "type": "string",
            "enum": ["website", "referral", "phone", "api", "walk_in", "migrated"],
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateCustomerRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255
          },
          "phone": {
            "type": "string",
            "maxLength": 20
          },
          "address": {
            "type": "string",
            "maxLength": 255
          },
          "city": {
            "type": "string",
            "maxLength": 100
          },
          "state": {
            "type": "string",
            "maxLength": 50
          },
          "zip": {
            "type": "string",
            "maxLength": 20
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 50
            }
          },
          "notes": {
            "type": "string",
            "maxLength": 5000
          },
          "source": {
            "type": "string",
            "enum": ["website", "referral", "phone", "api", "walk_in", "migrated"]
          }
        }
      },
      "UpdateCustomerRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "zip": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": ["website", "referral", "phone", "api", "walk_in", "migrated"]
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "CustomerResponse": {
        "type": "object",
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "CustomerDetailResponse": {
        "type": "object",
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "stats": {
            "type": "object",
            "properties": {
              "total_appointments": {
                "type": "integer"
              },
              "completed_appointments": {
                "type": "integer"
              },
              "cancelled_appointments": {
                "type": "integer"
              },
              "no_shows": {
                "type": "integer"
              },
              "last_appointment_date": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "first_appointment_date": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            }
          },
          "recent_appointments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Appointment"
            }
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "CustomerListResponse": {
        "type": "object",
        "properties": {
          "customers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Customer"
            }
          },
          "count": {
            "type": "integer"
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              },
              "total_pages": {
                "type": "integer"
              },
              "has_more": {
                "type": "boolean"
              }
            }
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "SendMessageRequest": {
        "type": "object",
        "required": ["type", "message"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["email", "sms"]
          },
          "subject": {
            "type": "string",
            "maxLength": 200,
            "description": "Email subject (optional, email only)"
          },
          "message": {
            "type": "string",
            "maxLength": 2000
          }
        }
      },
      "Location": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "timezone": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          },
          "employee_count": {
            "type": "integer"
          },
          "service_count": {
            "type": "integer"
          }
        }
      },
      "CreateLocationRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "zip": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "timezone": {
            "type": "string",
            "default": "America/New_York"
          }
        }
      },
      "UpdateLocationRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "zip": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          }
        }
      },
      "LocationResponse": {
        "type": "object",
        "properties": {
          "location": {
            "$ref": "#/components/schemas/Location"
          },
          "success": {
            "type": "boolean"
          }
        }
      },
      "LocationListResponse": {
        "type": "object",
        "properties": {
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Location"
            }
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "UpdateScheduleRequest": {
        "type": "object",
        "properties": {
          "employee_id": {
            "type": "string",
            "format": "uuid"
          },
          "day_of_week": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "start_time": {
            "type": "string",
            "example": "09:00"
          },
          "end_time": {
            "type": "string",
            "example": "17:00"
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "key_prefix": {
            "type": "string",
            "description": "First 12 characters of the key (e.g., oxb_abc123...)"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "is_active": {
            "type": "boolean"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "availability:read",
                "appointments:read",
                "appointments:write",
                "appointments:delete",
                "customers:read",
                "customers:write",
                "employees:read",
                "employees:write",
                "services:read",
                "services:write",
                "schedules:read",
                "schedules:write",
                "settings:read",
                "settings:write"
              ]
            },
            "description": "Defaults to booking_agent bundle if not specified"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "UpdateApiKeyRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "ApiKeyResponse": {
        "type": "object",
        "properties": {
          "key": {
            "$ref": "#/components/schemas/ApiKey"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "ApiKeyCreateResponse": {
        "type": "object",
        "properties": {
          "key": {
            "$ref": "#/components/schemas/ApiKey"
          },
          "api_key": {
            "type": "string",
            "description": "The full API key (only shown once, store securely)"
          },
          "message": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "ApiKeyListResponse": {
        "type": "object",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKey"
            }
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "SettingsResponse": {
        "type": "object",
        "properties": {
          "organization": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              },
              "timezone": {
                "type": "string"
              },
              "phone": {
                "type": "string",
                "nullable": true
              },
              "email": {
                "type": "string",
                "nullable": true
              },
              "website": {
                "type": "string",
                "nullable": true
              },
              "settings": {
                "type": "object",
                "properties": {
                  "require_phone": {
                    "type": "boolean"
                  },
                  "require_email": {
                    "type": "boolean"
                  },
                  "min_notice_hours": {
                    "type": "integer"
                  },
                  "max_advance_days": {
                    "type": "integer"
                  },
                  "default_appointment_duration": {
                    "type": "integer"
                  },
                  "buffer_between_appointments": {
                    "type": "integer"
                  },
                  "send_confirmation_email": {
                    "type": "boolean"
                  },
                  "send_reminder_email": {
                    "type": "boolean"
                  },
                  "reminder_hours_before": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      },
      "UpdateSettingsRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "settings": {
            "type": "object",
            "properties": {
              "require_phone": {
                "type": "boolean"
              },
              "require_email": {
                "type": "boolean"
              },
              "min_notice_hours": {
                "type": "integer"
              },
              "max_advance_days": {
                "type": "integer"
              },
              "default_appointment_duration": {
                "type": "integer"
              },
              "buffer_between_appointments": {
                "type": "integer"
              },
              "send_confirmation_email": {
                "type": "boolean"
              },
              "send_reminder_email": {
                "type": "boolean"
              },
              "reminder_hours_before": {
                "type": "integer"
              }
            }
          }
        }
      },
      "EmbedConfigResponse": {
        "type": "object",
        "description": "Configuration for the embeddable booking widget",
        "properties": {
          "organization": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Organization ID"
              },
              "name": {
                "type": "string",
                "description": "Organization display name"
              },
              "slug": {
                "type": "string",
                "description": "URL-friendly identifier"
              },
              "timezone": {
                "type": "string",
                "description": "Organization timezone (IANA format)",
                "example": "America/New_York"
              },
              "settings": {
                "type": "object",
                "properties": {
                  "require_phone": {
                    "type": "boolean",
                    "description": "Whether phone number is required for booking"
                  },
                  "require_email": {
                    "type": "boolean",
                    "description": "Whether email is required for booking"
                  },
                  "min_notice_hours": {
                    "type": "integer",
                    "description": "Minimum hours notice required for booking"
                  },
                  "max_advance_days": {
                    "type": "integer",
                    "description": "Maximum days in advance booking is allowed"
                  }
                }
              }
            }
          },
          "services": {
            "type": "array",
            "description": "Available services for booking",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "duration_minutes": {
                  "type": "integer"
                },
                "price_cents": {
                  "type": "integer",
                  "description": "Price in cents (e.g., 15000 = $150.00)"
                },
                "color": {
                  "type": "string",
                  "description": "Hex color for display"
                }
              }
            }
          }
        }
      },
      "DomainErrorResponse": {
        "type": "object",
        "description": "Error response for domain validation failures",
        "properties": {
          "error": {
            "type": "string",
            "description": "Short error description",
            "example": "Unauthorized domain"
          },
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "This domain is not authorized to access the booking widget."
          },
          "code": {
            "type": "string",
            "description": "Machine-readable error code",
            "enum": ["DOMAIN_NOT_ALLOWED", "NO_ORIGIN"],
            "example": "DOMAIN_NOT_ALLOWED"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          },
          "hint": {
            "type": "string",
            "description": "Helpful hint for resolving the error"
          },
          "details": {
            "type": "object",
            "description": "Additional error details"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "date parameter is required",
              "hint": "Use format YYYY-MM-DD"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Invalid API key"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Appointment not found"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient permissions - API key lacks required scope",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Insufficient permissions. Required scope: appointments:write"
            }
          }
        }
      },
      "DomainForbidden": {
        "description": "Domain not authorized to access the booking widget. The requesting domain is not in the organization's allowlist.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DomainErrorResponse"
            },
            "example": {
              "error": "Unauthorized domain",
              "message": "This domain is not authorized to access the booking widget. Please contact the organization administrator.",
              "code": "DOMAIN_NOT_ALLOWED"
            }
          }
        }
      }
    }
  }
}
