{
  "openapi": "3.0.0",
  "paths": {
    "/integrations/oauth/token": {
      "post": {
        "description": "Exchanges a `client_id` and `client_secret` for a short-lived JWT bearer token. Use the token in the `Authorization: Bearer <token>` header on Integration API endpoints.",
        "operationId": "IntegrationOauthController_issueToken",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueTokenDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssueTokenResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Invalid client credentials",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_client",
                    "message": "Invalid client credentials"
                  }
                }
              }
            }
          }
        },
        "summary": "Issue an M2M access token (OAuth2 client_credentials)",
        "tags": [
          "Integration API — OAuth"
        ],
        "security": []
      }
    },
    "/integrations/v1/providers/{providerId}/catalog": {
      "get": {
        "operationId": "IntegrationCatalogController_getCatalog",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): catalog:read"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "catalog:read"
            ]
          }
        ],
        "summary": "Get booking catalog for voicebot and external booking clients",
        "tags": [
          "Integration API — Catalog"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/catalog/employees/search": {
      "get": {
        "operationId": "IntegrationCatalogController_searchEmployees",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "q",
            "required": true,
            "in": "query",
            "schema": {
              "minLength": 1,
              "maxLength": 120,
              "type": "string"
            }
          },
          {
            "name": "employeeId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 25,
              "default": 10,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): catalog:read"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "catalog:read"
            ]
          }
        ],
        "summary": "Search active employees by name, optionally for a service",
        "tags": [
          "Integration API — Catalog"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/catalog/resolve": {
      "post": {
        "operationId": "IntegrationCatalogController_resolve",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResolveIntegrationCatalogDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): catalog:read"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "catalog:read"
            ]
          }
        ],
        "summary": "Resolve spoken service and employee names into booking candidates",
        "tags": [
          "Integration API — Catalog"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/catalog/services/search": {
      "get": {
        "operationId": "IntegrationCatalogController_searchServices",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "q",
            "required": true,
            "in": "query",
            "schema": {
              "minLength": 1,
              "maxLength": 120,
              "type": "string"
            }
          },
          {
            "name": "employeeId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 25,
              "default": 10,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): catalog:read"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "catalog:read"
            ]
          }
        ],
        "summary": "Search active services by name, optionally for an employee",
        "tags": [
          "Integration API — Catalog"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/clients": {
      "post": {
        "description": "Creates a provider-scoped client record for external CRM and booking flows. The integration token must contain the `clients:create` scope.",
        "operationId": "IntegrationProviderClientsController_create",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProviderClientDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderClientResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "clients:create"
            ]
          }
        ],
        "summary": "Create provider client",
        "tags": [
          "Integration API — Clients"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/clients/identify": {
      "post": {
        "description": "Returns a minimal, provider-scoped result for voicebot caller recognition. Caller ID is a recognition signal, not authentication, and this endpoint never returns client contact or profile data.",
        "operationId": "IntegrationProviderClientsController_identify",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdentifyIntegrationProviderClientDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationProviderClientIdentificationDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "clients:identify"
            ]
          }
        ],
        "summary": "Identify a provider client by an exact caller phone number",
        "tags": [
          "Integration API — Clients"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/clients/search": {
      "get": {
        "description": "Returns full provider-scoped client records for trusted CRM and provider-operated booking flows. For caller recognition use the minimal exact-phone identify endpoint. The integration token must contain the `clients:read` scope.",
        "operationId": "IntegrationProviderClientsController_search",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Search phrase matched against name, email, or phone.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 25,
              "default": 10,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProviderClientResponseDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "clients:read"
            ]
          }
        ],
        "summary": "Search provider clients by name, email, or phone",
        "tags": [
          "Integration API — Clients"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/clients/{id}": {
      "patch": {
        "description": "Updates a provider-scoped client record for external CRM and booking flows. The integration token must contain the `clients:update` scope.",
        "operationId": "IntegrationProviderClientsController_update",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProviderClientDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderClientResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "clients:update"
            ]
          }
        ],
        "summary": "Update provider client",
        "tags": [
          "Integration API — Clients"
        ]
      },
      "delete": {
        "description": "Soft-deletes a provider-scoped client record. The integration token must contain the `clients:delete` scope.",
        "operationId": "IntegrationProviderClientsController_remove",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "clients:delete"
            ]
          }
        ],
        "summary": "Delete provider client",
        "tags": [
          "Integration API — Clients"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/reservations": {
      "get": {
        "operationId": "IntegrationReservationsController_list",
        "parameters": [
          {
            "name": "startsAfter",
            "required": false,
            "in": "query",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "startsBefore",
            "required": false,
            "in": "query",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "employeeId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "type": "number"
            }
          },
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:read"
            ]
          }
        ],
        "summary": "List reservations for the authenticated provider",
        "tags": [
          "Integration API — Reservations"
        ]
      },
      "post": {
        "operationId": "IntegrationReservationsController_create",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Caller-supplied unique key (per integration client) for at-most-once reservation creation. A replay with the same request returns the original reservation.",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 180
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateIntegrationReservationDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Reservation created",
            "headers": {
              "Idempotency-Replayed": {
                "description": "Present with value true when an earlier reservation is replayed",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Slot conflict or idempotency-key body mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:create"
            ]
          }
        ],
        "summary": "Create a reservation",
        "tags": [
          "Integration API — Reservations"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/reservations/{reservationId}": {
      "get": {
        "operationId": "IntegrationReservationsController_findOne",
        "parameters": [
          {
            "name": "reservationId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:read"
            ]
          }
        ],
        "summary": "Get a single reservation",
        "tags": [
          "Integration API — Reservations"
        ]
      },
      "patch": {
        "operationId": "IntegrationReservationsController_update",
        "parameters": [
          {
            "name": "reservationId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateIntegrationReservationDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:update"
            ]
          }
        ],
        "summary": "Modify a reservation time or duration",
        "tags": [
          "Integration API — Reservations"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/reservations/{reservationId}/cancel": {
      "post": {
        "operationId": "IntegrationReservationsController_cancel",
        "parameters": [
          {
            "name": "reservationId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancelIntegrationReservationDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:cancel"
            ]
          }
        ],
        "summary": "Cancel a reservation",
        "tags": [
          "Integration API — Reservations"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/reservations/{reservationId}/events": {
      "get": {
        "operationId": "IntegrationReservationsController_findEvents",
        "parameters": [
          {
            "name": "reservationId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:history:read"
            ]
          }
        ],
        "summary": "List reservation lifecycle events",
        "tags": [
          "Integration API — Reservations"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/reservations/{reservationId}/reschedule": {
      "patch": {
        "operationId": "IntegrationReservationsController_reschedule",
        "parameters": [
          {
            "name": "reservationId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateIntegrationReservationDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): reservations:create"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "reservations:reschedule"
            ]
          }
        ],
        "summary": "Reschedule a reservation using client-side provider policy rules",
        "tags": [
          "Integration API — Reservations"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/slots": {
      "get": {
        "description": "Returns slots grouped by date for the given service. The integration token must contain the `slots:read` scope and match the provider in the path.",
        "operationId": "IntegrationSlotsController_list",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "required": true,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "required": true,
            "in": "query",
            "schema": {
              "format": "date",
              "example": "2026-05-20",
              "type": "string"
            }
          },
          {
            "name": "dateTo",
            "required": true,
            "in": "query",
            "schema": {
              "format": "date",
              "example": "2026-05-22",
              "type": "string"
            }
          },
          {
            "name": "employeeId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "schema": {
              "example": "Europe/Warsaw",
              "type": "string"
            }
          },
          {
            "name": "timeFrom",
            "required": false,
            "in": "query",
            "schema": {
              "example": "16:00",
              "type": "string"
            }
          },
          {
            "name": "timeTo",
            "required": false,
            "in": "query",
            "schema": {
              "example": "20:00",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slots grouped by date"
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): slots:read"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "slots:read"
            ]
          }
        ],
        "summary": "List available slots for a service in a date range",
        "tags": [
          "Integration API — Slots"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/slots/first-available": {
      "get": {
        "description": "Returns the first available slot within the requested horizon. The integration token must contain the `slots:read` scope and match the provider in the path.",
        "operationId": "IntegrationSlotsController_findFirstAvailable",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "required": true,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "employeeId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "inDays",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 90,
              "default": 30,
              "type": "number"
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "schema": {
              "example": "Europe/Warsaw",
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "required": false,
            "in": "query",
            "description": "Inclusive lower date bound.",
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "name": "dateTo",
            "required": false,
            "in": "query",
            "description": "Inclusive upper date bound.",
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "name": "direction",
            "required": false,
            "in": "query",
            "schema": {
              "default": "forward",
              "type": "string",
              "enum": [
                "forward",
                "backward"
              ]
            }
          },
          {
            "name": "slotPreference",
            "required": false,
            "in": "query",
            "schema": {
              "default": "earliest",
              "type": "string",
              "enum": [
                "earliest",
                "latest"
              ]
            }
          },
          {
            "name": "timeFrom",
            "required": false,
            "in": "query",
            "schema": {
              "example": "16:00",
              "type": "string"
            }
          },
          {
            "name": "timeTo",
            "required": false,
            "in": "query",
            "schema": {
              "example": "20:00",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "First available slot"
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "invalid_token",
                    "message": "Token is missing, invalid or expired"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing scope or provider mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "error": "insufficient_scope",
                    "message": "Missing required scope(s): slots:read"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "slots:read"
            ]
          }
        ],
        "summary": "Find the first available slot for a service",
        "tags": [
          "Integration API — Slots"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/webhooks": {
      "get": {
        "operationId": "IntegrationWebhooksController_list",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookResponseDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:read"
            ]
          }
        ],
        "summary": "List webhooks owned by the authenticated integration client",
        "tags": [
          "Integration API — Webhooks"
        ]
      },
      "post": {
        "description": "The webhook is automatically linked to the OAuth client. The signing secret is returned exactly once.",
        "operationId": "IntegrationWebhooksController_create",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateIntegrationWebhookDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreatedDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:write"
            ]
          }
        ],
        "summary": "Create a webhook owned by the authenticated integration client",
        "tags": [
          "Integration API — Webhooks"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/webhooks/{id}": {
      "patch": {
        "operationId": "IntegrationWebhooksController_update",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateIntegrationWebhookDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:write"
            ]
          }
        ],
        "summary": "Update a webhook owned by the authenticated integration client",
        "tags": [
          "Integration API — Webhooks"
        ]
      },
      "delete": {
        "operationId": "IntegrationWebhooksController_remove",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:write"
            ]
          }
        ],
        "summary": "Delete a webhook owned by the authenticated integration client",
        "tags": [
          "Integration API — Webhooks"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "IntegrationWebhooksController_listDeliveries",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDeliveryResponseDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:read"
            ]
          }
        ],
        "summary": "List recent delivery attempts for a webhook",
        "tags": [
          "Integration API — Webhooks"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/webhooks/{id}/rotate-secret": {
      "post": {
        "description": "Returns the replacement secret exactly once. Requires the separate `webhooks:secret:rotate` scope.",
        "operationId": "IntegrationWebhooksController_rotateSecret",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreatedDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:secret:rotate"
            ]
          }
        ],
        "summary": "Rotate a webhook signing secret",
        "tags": [
          "Integration API — Webhooks"
        ]
      }
    },
    "/integrations/v1/providers/{providerId}/webhooks/{id}/test": {
      "post": {
        "operationId": "IntegrationWebhooksController_test",
        "parameters": [
          {
            "name": "providerId",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryResponseDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token"
          },
          "403": {
            "description": "Missing scope or provider mismatch"
          },
          "429": {
            "description": "Integration client rate limit exceeded"
          }
        },
        "security": [
          {
            "integrationOAuth": [
              "webhooks:test"
            ]
          }
        ],
        "summary": "Enqueue a test webhook delivery",
        "tags": [
          "Integration API — Webhooks"
        ]
      }
    }
  },
  "info": {
    "title": "Umovi Integration API",
    "description": "OAuth2 machine-to-machine API for provider booking integrations.",
    "version": "1.0.0",
    "contact": {}
  },
  "tags": [
    {
      "name": "Integration API — OAuth",
      "description": "OAuth2 client credentials token endpoint."
    },
    {
      "name": "Integration API — Catalog",
      "description": "Integration catalog discovery."
    },
    {
      "name": "Integration API — Clients",
      "description": "Integration provider-client lookup."
    },
    {
      "name": "Integration API — Slots",
      "description": "Integration availability slot lookup."
    },
    {
      "name": "Integration API — Reservations",
      "description": "Integration reservation lifecycle."
    },
    {
      "name": "Integration API — Webhooks",
      "description": "Integration webhook subscriptions."
    }
  ],
  "servers": [
    {
      "url": "https://u-api.m-cloud.pl",
      "description": "Integration API server"
    }
  ],
  "components": {
    "securitySchemes": {
      "integrationOAuth": {
        "type": "oauth2",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://u-api.m-cloud.pl/integrations/oauth/token",
            "scopes": {
              "catalog:read": "Read booking catalog, search and resolve services and employees.",
              "services:internal:use": "Use internal-only services in catalog, slots and reservation creation when combined with the relevant operation scope.",
              "clients:identify": "Identify a provider client from an exact phone number without returning profile or contact data.",
              "clients:read": "Search provider clients.",
              "clients:create": "Create provider clients.",
              "clients:update": "Update provider clients.",
              "clients:delete": "Delete provider clients.",
              "slots:read": "Read availability slots.",
              "reservations:create": "Create reservations.",
              "reservations:read": "Read reservations.",
              "reservations:history:read": "Read reservation lifecycle history.",
              "reservations:update": "Update reservations.",
              "reservations:reschedule": "Reschedule reservations as the client.",
              "reservations:cancel": "Cancel reservations.",
              "webhooks:read": "Read integration-owned webhooks and delivery attempts.",
              "webhooks:write": "Create, update and delete integration-owned webhooks.",
              "webhooks:secret:rotate": "Rotate webhook signing secrets.",
              "webhooks:test": "Enqueue test webhook deliveries."
            }
          }
        }
      }
    },
    "schemas": {
      "MarketingConsentEvidenceDto": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "IN_PERSON",
              "PHONE",
              "WRITTEN",
              "WEB_FORM"
            ]
          },
          "statementVersion": {
            "type": "string",
            "maxLength": 64
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        },
        "required": [
          "method",
          "statementVersion"
        ]
      },
      "CreateProviderClientDto": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "maxLength": 30
          },
          "emailNotificationsEnabled": {
            "type": "boolean",
            "default": true,
            "description": "Allow email communication for a client without a linked Umovi account."
          },
          "smsNotificationsEnabled": {
            "type": "boolean",
            "default": true,
            "description": "Allow SMS communication for a client without a linked Umovi account."
          },
          "marketingEnabled": {
            "type": "boolean",
            "default": false
          },
          "marketingConsentEvidence": {
            "$ref": "#/components/schemas/MarketingConsentEvidenceDto"
          },
          "isReturningClientManual": {
            "type": "boolean",
            "default": false,
            "description": "Marks this provider client as a returning client manually."
          },
          "consentGiven": {
            "type": "boolean",
            "description": "Consent to process client contact data. Must be true on create."
          },
          "sendInvite": {
            "type": "boolean",
            "description": "Send account invite when email is provided and no CLIENT account exists yet."
          }
        },
        "required": [
          "consentGiven"
        ]
      },
      "ProviderClientResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          },
          "deletedAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "providerId": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "firstName": {
            "type": "object",
            "nullable": true
          },
          "lastName": {
            "type": "object",
            "nullable": true
          },
          "email": {
            "type": "object",
            "nullable": true
          },
          "phone": {
            "type": "object",
            "nullable": true
          },
          "emailNotificationsEnabled": {
            "type": "boolean"
          },
          "smsNotificationsEnabled": {
            "type": "boolean"
          },
          "marketingEnabled": {
            "type": "boolean"
          },
          "isReturningClientManual": {
            "type": "boolean"
          },
          "isReturningClientAuto": {
            "type": "boolean"
          },
          "isReturningClient": {
            "type": "boolean"
          },
          "returningClientAutoMarkedAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "consentGivenAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "displayName": {
            "type": "string"
          },
          "displayEmail": {
            "type": "object",
            "nullable": true
          },
          "displayPhone": {
            "type": "object",
            "nullable": true
          },
          "avatarUrl": {
            "type": "object",
            "nullable": true
          },
          "userFirstName": {
            "type": "object",
            "nullable": true
          },
          "userLastName": {
            "type": "object",
            "nullable": true
          },
          "userEmail": {
            "type": "object",
            "nullable": true
          },
          "userPhone": {
            "type": "object",
            "nullable": true
          }
        },
        "required": [
          "id",
          "createdAt",
          "updatedAt",
          "deletedAt",
          "providerId",
          "userId",
          "firstName",
          "lastName",
          "email",
          "phone",
          "emailNotificationsEnabled",
          "smsNotificationsEnabled",
          "marketingEnabled",
          "isReturningClientManual",
          "isReturningClientAuto",
          "isReturningClient",
          "returningClientAutoMarkedAt",
          "consentGivenAt",
          "displayName",
          "displayEmail",
          "displayPhone",
          "avatarUrl",
          "userFirstName",
          "userLastName",
          "userEmail",
          "userPhone"
        ]
      },
      "UpdateProviderClientDto": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "maxLength": 30
          },
          "emailNotificationsEnabled": {
            "type": "boolean",
            "description": "Allow email communication for a client without a linked Umovi account."
          },
          "smsNotificationsEnabled": {
            "type": "boolean",
            "description": "Allow SMS communication for a client without a linked Umovi account."
          },
          "marketingEnabled": {
            "type": "boolean"
          },
          "marketingConsentEvidence": {
            "$ref": "#/components/schemas/MarketingConsentEvidenceDto"
          },
          "isReturningClientManual": {
            "type": "boolean",
            "default": false,
            "description": "Marks this provider client as a returning client manually."
          },
          "consentGiven": {
            "type": "boolean",
            "description": "Set to false to revoke consent, unlink account and soft-delete provider client record."
          },
          "sendInvite": {
            "type": "boolean",
            "description": "Send account invite when email is provided and no CLIENT account exists yet."
          }
        }
      },
      "Booking": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          },
          "deletedAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "providerId": {
            "type": "string",
            "format": "uuid"
          },
          "serviceId": {
            "type": "string",
            "format": "uuid"
          },
          "serviceName": {
            "type": "object",
            "nullable": true
          },
          "serviceDescription": {
            "type": "object",
            "nullable": true
          },
          "serviceDurationMinutes": {
            "type": "object",
            "nullable": true
          },
          "serviceBufferMinutes": {
            "type": "object",
            "nullable": true
          },
          "servicePriceCents": {
            "type": "object",
            "nullable": true
          },
          "serviceOriginalPriceCents": {
            "type": "object",
            "nullable": true
          },
          "servicePromotionId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "servicePromotionName": {
            "type": "object",
            "nullable": true
          },
          "servicePromotionType": {
            "type": "string",
            "nullable": true,
            "enum": [
              "PERCENTAGE",
              "FIXED_AMOUNT"
            ]
          },
          "serviceDiscountPercent": {
            "type": "object",
            "nullable": true
          },
          "serviceDiscountAmountCents": {
            "type": "object",
            "nullable": true
          },
          "serviceOmnibusMinPriceCents": {
            "type": "object",
            "nullable": true
          },
          "serviceCurrency": {
            "type": "object",
            "example": "USD",
            "nullable": true
          },
          "serviceCategoryId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "serviceCategory": {
            "type": "object",
            "nullable": true
          },
          "employeeId": {
            "type": "string",
            "format": "uuid"
          },
          "employeeDisplayName": {
            "type": "object",
            "nullable": true
          },
          "workstationId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "workstationName": {
            "type": "object",
            "nullable": true
          },
          "clientId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "providerClientId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "clientEmail": {
            "type": "object",
            "nullable": true
          },
          "clientFirstName": {
            "type": "object",
            "nullable": true
          },
          "clientLastName": {
            "type": "object",
            "nullable": true
          },
          "clientPhone": {
            "type": "object",
            "nullable": true
          },
          "providerName": {
            "type": "object",
            "nullable": true
          },
          "providerSlug": {
            "type": "object",
            "nullable": true
          },
          "providerLogoUrl": {
            "type": "object",
            "nullable": true
          },
          "providerTimezone": {
            "type": "object",
            "nullable": true
          },
          "serviceBookingCode": {
            "type": "string",
            "nullable": true,
            "description": "Current public booking code for the booked service. Null when the service can no longer be booked publicly."
          },
          "employeeBookingCode": {
            "type": "string",
            "nullable": true,
            "description": "Current public booking code for the booked employee. Null when the employee is no longer eligible for the service."
          },
          "providerDefaultLanguage": {
            "type": "object",
            "nullable": true,
            "description": "Provider default language for client communications (BCP-47)."
          },
          "providerCountry": {
            "type": "object",
            "nullable": true,
            "description": "Provider ISO 3166-1 alpha-2 country code."
          },
          "originEventId": {
            "type": "object",
            "nullable": true,
            "description": "Lifecycle event id that created this booking."
          },
          "originActorType": {
            "type": "string",
            "enum": [
              "CLIENT",
              "PROVIDER",
              "ADMIN",
              "INTEGRATION",
              "SYSTEM",
              "UNKNOWN"
            ],
            "nullable": true
          },
          "originActorUserId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "originActorRole": {
            "type": "object",
            "nullable": true
          },
          "originActorLabelSnapshot": {
            "type": "object",
            "nullable": true
          },
          "originSourceChannel": {
            "type": "string",
            "enum": [
              "INTERNAL_API",
              "INTEGRATION",
              "MCP",
              "SYSTEM"
            ],
            "nullable": true
          },
          "originSourceSurface": {
            "type": "string",
            "enum": [
              "CLIENT_WEB",
              "PROVIDER_WEB",
              "ADMIN_WEB",
              "BRAND_WEB",
              "CLIENT_ANDROID",
              "CLIENT_IOS",
              "PROVIDER_IOS",
              "INTEGRATION_API",
              "MCP",
              "SYSTEM_WORKER",
              "OTHER_APP",
              "UNKNOWN"
            ],
            "nullable": true
          },
          "originIntegrationClientId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "originIntegrationClientName": {
            "type": "object",
            "nullable": true
          },
          "originOccurredAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "startsAt": {
            "format": "date-time",
            "type": "string"
          },
          "serviceEndsAt": {
            "format": "date-time",
            "type": "string"
          },
          "endsAt": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "RESCHEDULE_REQUESTED",
              "CONFIRMED",
              "CANCELLED",
              "WITHDRAWN",
              "COMPLETED",
              "NO_SHOW"
            ]
          },
          "lookupCode": {
            "type": "string",
            "description": "Short human-friendly lookup code for active and recent bookings.",
            "example": "4Z9K0HN"
          },
          "lookupCodeState": {
            "type": "string",
            "enum": [
              "SEARCHABLE",
              "QUARANTINED",
              "RELEASED"
            ]
          },
          "lookupCodeSearchableUntil": {
            "format": "date-time",
            "type": "string"
          },
          "lookupCodeReusableAfter": {
            "format": "date-time",
            "type": "string"
          },
          "lookupCodeReleasedAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "doesNotBlockClientSlots": {
            "type": "boolean",
            "default": false,
            "description": "When true, this booking is ignored by client-facing slot availability and slot conflict checks."
          },
          "cancellationReason": {
            "type": "object",
            "nullable": true
          },
          "cancelledAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "reminderSentAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "reminderLastAttemptAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "rescheduleAllowed": {
            "type": "boolean",
            "description": "Whether the current client may reschedule this booking under provider policy."
          },
          "rescheduleUnavailableReason": {
            "type": "object",
            "nullable": true,
            "description": "Machine-readable reason why client reschedule is unavailable."
          },
          "rescheduleNoticeMinutes": {
            "type": "object",
            "nullable": true,
            "description": "Minimum notice before current start, in minutes, required by provider policy."
          },
          "clientAvatarUrl": {
            "type": "object",
            "nullable": true
          }
        },
        "required": [
          "id",
          "createdAt",
          "updatedAt",
          "deletedAt",
          "providerId",
          "serviceId",
          "serviceName",
          "serviceDescription",
          "serviceDurationMinutes",
          "serviceBufferMinutes",
          "servicePriceCents",
          "serviceOriginalPriceCents",
          "servicePromotionId",
          "servicePromotionName",
          "servicePromotionType",
          "serviceDiscountPercent",
          "serviceDiscountAmountCents",
          "serviceOmnibusMinPriceCents",
          "serviceCurrency",
          "serviceCategoryId",
          "serviceCategory",
          "employeeId",
          "employeeDisplayName",
          "workstationId",
          "workstationName",
          "clientId",
          "providerClientId",
          "clientEmail",
          "clientFirstName",
          "clientLastName",
          "clientPhone",
          "providerName",
          "providerSlug",
          "providerLogoUrl",
          "providerTimezone",
          "startsAt",
          "serviceEndsAt",
          "endsAt",
          "status",
          "lookupCode",
          "lookupCodeState",
          "lookupCodeSearchableUntil",
          "lookupCodeReusableAfter",
          "lookupCodeReleasedAt",
          "doesNotBlockClientSlots",
          "cancellationReason",
          "cancelledAt",
          "reminderSentAt",
          "reminderLastAttemptAt",
          "clientAvatarUrl"
        ]
      },
      "ResolveIntegrationCatalogDto": {
        "type": "object",
        "properties": {
          "serviceName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "employeeName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "limit": {
            "type": "number",
            "default": 10,
            "minimum": 1,
            "maximum": 25
          }
        }
      },
      "IssueTokenDto": {
        "type": "object",
        "properties": {
          "client_id": {
            "type": "string",
            "example": "umovi_voicebot_abc123"
          },
          "client_secret": {
            "type": "string",
            "example": "generated-secret-visible-only-once"
          },
          "grant_type": {
            "type": "string",
            "example": "client_credentials",
            "enum": [
              "client_credentials"
            ]
          },
          "scope": {
            "type": "string",
            "example": "slots:read reservations:create"
          }
        },
        "required": [
          "client_id",
          "client_secret"
        ]
      },
      "IssueTokenResponseDto": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "number",
            "example": 1800
          },
          "scope": {
            "type": "string",
            "example": "slots:read reservations:create"
          }
        },
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "scope"
        ]
      },
      "IdentifyIntegrationProviderClientDto": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string",
            "example": "+48123456789",
            "description": "Caller phone number. It is normalized and matched exactly in E.164 form."
          }
        },
        "required": [
          "phone"
        ]
      },
      "IntegrationProviderClientIdentificationDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "MATCHED",
              "NOT_FOUND",
              "AMBIGUOUS"
            ]
          },
          "providerClientId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        },
        "required": [
          "status",
          "providerClientId"
        ]
      },
      "IntegrationReservationClientDto": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "maxLength": 30,
            "description": "Required when email is not provided. Must use E.164 format."
          }
        },
        "required": [
          "firstName"
        ]
      },
      "CreateIntegrationReservationDto": {
        "type": "object",
        "properties": {
          "serviceId": {
            "type": "string",
            "format": "uuid"
          },
          "employeeId": {
            "type": "string",
            "format": "uuid",
            "description": "Required for SPECIFIC and omitted for ANY employee selection."
          },
          "employeeSelectionMode": {
            "type": "string",
            "enum": [
              "SPECIFIC",
              "ANY"
            ],
            "description": "SPECIFIC requires employeeId. ANY lets the backend allocate an eligible available employee atomically."
          },
          "startAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-05-17T10:00:00+02:00"
          },
          "startsAt": {
            "type": "string",
            "format": "date-time",
            "description": "Alias accepted for compatibility with internal booking APIs.",
            "example": "2026-05-17T10:00:00+02:00"
          },
          "providerClientId": {
            "type": "string",
            "format": "uuid"
          },
          "client": {
            "description": "Provider-scoped client contact. Contact data never creates or silently links a global Umovi account. An unlinked client can claim the record later from guest booking communication.",
            "allOf": [
              {
                "$ref": "#/components/schemas/IntegrationReservationClientDto"
              }
            ]
          },
          "internalNote": {
            "type": "string",
            "maxLength": 2000,
            "description": "Provider-only operational note attached to the reservation. It is never shown to the client or included in client communication."
          },
          "source": {
            "type": "string",
            "description": "Source identifier (e.g. \"voicebot\", \"crm\")",
            "maxLength": 80
          },
          "externalReservationId": {
            "type": "string",
            "description": "Caller-side reservation id, used together with Idempotency-Key for at-most-once semantics",
            "maxLength": 120
          }
        },
        "required": [
          "serviceId",
          "startAt"
        ]
      },
      "UpdateIntegrationReservationDto": {
        "type": "object",
        "properties": {
          "startAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-05-17T11:00:00+02:00"
          },
          "startsAt": {
            "type": "string",
            "format": "date-time",
            "description": "Alias accepted for compatibility with internal booking APIs.",
            "example": "2026-05-17T11:00:00+02:00"
          },
          "serviceDurationMinutes": {
            "type": "number",
            "minimum": 5,
            "maximum": 600
          },
          "ignoreBuffer": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "CancelIntegrationReservationDto": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 500,
            "example": "Cancelled by external system"
          }
        }
      },
      "WebhookResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "providerId": {
            "type": "string",
            "format": "uuid"
          },
          "integrationId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "booking.created",
                "booking.updated",
                "booking.client_assigned",
                "booking.reminder_sent",
                "booking.message_created",
                "booking.confirmed",
                "booking.status_changed",
                "booking.rescheduled",
                "booking.cancelled",
                "booking.cancelled_by_client",
                "booking.completed",
                "booking.no_show",
                "booking.deleted",
                "client.created",
                "client.updated",
                "client.deleted",
                "billing.payment.paid",
                "billing.document.ready"
              ]
            }
          },
          "isActive": {
            "type": "boolean"
          },
          "consecutiveFailures": {
            "type": "number"
          },
          "lastSuccessAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "lastFailureAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "disabledAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "disabledReason": {
            "type": "object",
            "nullable": true
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "providerId",
          "integrationId",
          "url",
          "events",
          "isActive",
          "consecutiveFailures",
          "lastSuccessAt",
          "lastFailureAt",
          "disabledAt",
          "disabledReason",
          "createdAt",
          "updatedAt"
        ]
      },
      "CreateIntegrationWebhookDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "example": "https://example.com/umovi/webhooks"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "booking.created",
                "booking.updated",
                "booking.client_assigned",
                "booking.reminder_sent",
                "booking.message_created",
                "booking.confirmed",
                "booking.status_changed",
                "booking.rescheduled",
                "booking.cancelled",
                "booking.cancelled_by_client",
                "booking.completed",
                "booking.no_show",
                "booking.deleted",
                "client.created",
                "client.updated",
                "client.deleted",
                "billing.payment.paid",
                "billing.document.ready"
              ]
            }
          },
          "isActive": {
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "url",
          "events"
        ]
      },
      "WebhookCreatedDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "providerId": {
            "type": "string",
            "format": "uuid"
          },
          "integrationId": {
            "type": "object",
            "format": "uuid",
            "nullable": true
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "booking.created",
                "booking.updated",
                "booking.client_assigned",
                "booking.reminder_sent",
                "booking.message_created",
                "booking.confirmed",
                "booking.status_changed",
                "booking.rescheduled",
                "booking.cancelled",
                "booking.cancelled_by_client",
                "booking.completed",
                "booking.no_show",
                "booking.deleted",
                "client.created",
                "client.updated",
                "client.deleted",
                "billing.payment.paid",
                "billing.document.ready"
              ]
            }
          },
          "isActive": {
            "type": "boolean"
          },
          "consecutiveFailures": {
            "type": "number"
          },
          "lastSuccessAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "lastFailureAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "disabledAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "disabledReason": {
            "type": "object",
            "nullable": true
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          },
          "secret": {
            "type": "string",
            "description": "Plain-text signing secret. Shown once; use it to verify HMAC signatures."
          }
        },
        "required": [
          "id",
          "providerId",
          "integrationId",
          "url",
          "events",
          "isActive",
          "consecutiveFailures",
          "lastSuccessAt",
          "lastFailureAt",
          "disabledAt",
          "disabledReason",
          "createdAt",
          "updatedAt",
          "secret"
        ]
      },
      "UpdateIntegrationWebhookDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "booking.created",
                "booking.updated",
                "booking.client_assigned",
                "booking.reminder_sent",
                "booking.message_created",
                "booking.confirmed",
                "booking.status_changed",
                "booking.rescheduled",
                "booking.cancelled",
                "booking.cancelled_by_client",
                "booking.completed",
                "booking.no_show",
                "booking.deleted",
                "client.created",
                "client.updated",
                "client.deleted",
                "billing.payment.paid",
                "billing.document.ready"
              ]
            }
          },
          "isActive": {
            "type": "boolean"
          }
        }
      },
      "WebhookDeliveryResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "webhookId": {
            "type": "string",
            "format": "uuid"
          },
          "providerId": {
            "type": "string",
            "format": "uuid"
          },
          "eventType": {
            "type": "string",
            "enum": [
              "webhook.test",
              "booking.created",
              "booking.updated",
              "booking.client_assigned",
              "booking.reminder_sent",
              "booking.message_created",
              "booking.confirmed",
              "booking.status_changed",
              "booking.rescheduled",
              "booking.cancelled",
              "booking.cancelled_by_client",
              "booking.completed",
              "booking.no_show",
              "booking.deleted",
              "client.created",
              "client.updated",
              "client.deleted",
              "billing.payment.paid",
              "billing.document.ready"
            ]
          },
          "payload": {
            "type": "object"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "success",
              "failed"
            ]
          },
          "attempts": {
            "type": "number"
          },
          "nextAttemptAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "lastError": {
            "type": "object",
            "nullable": true
          },
          "deliveredAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "webhookId",
          "providerId",
          "eventType",
          "payload",
          "status",
          "attempts",
          "nextAttemptAt",
          "lastError",
          "deliveredAt",
          "createdAt",
          "updatedAt"
        ]
      }
    }
  }
}
