{
  "openapi": "3.1.0",
  "info": {
    "title": "Sodtrack Tenant API",
    "version": "1.0.0",
    "summary": "Connect your own systems to Sodtrack",
    "description": "### 🚀 **Sodtrack Integration API**\n\nWelcome to the **Sodtrack Integration API Documentation** — your comprehensive guide to integrating seamlessly with Sodtrack’s Service Management ecosystem.\n\nThe Sodtrack API enables organizations to connect their systems directly with Sodtrack’s operational platform, facilitating real-time automation of service bookings, project management, lead generation, and contractor coordination.\n\nDesigned for scalability, security, and efficiency, this API provides the foundation for integrating Sodtrack’s core functionalities — including scheduling, catalog synchronization, coverage validation, and transactional workflows — into your existing business processes or digital channels.\n\n#### **Key Capabilities**\n\n-   **Authentication and Security:** Token-based access using JWT for secure API communication.\n    \n-   **Service Catalog:** Retrieve and manage categories, services, and variants available in the Sodtrack ecosystem.\n    \n-   **Coverage and Availability:** Validate geographical coverage and check contractor or time-slot availability in real time.\n    \n-   **Bookings:** Create, update, and manage service bookings directly from your systems.\n    \n-   **Projects and Transactions:** Link multiple bookings under project stages, attach documentation, register payments, and synchronize task updates.\n    \n-   **Lead Management:** Integrate Sodtrack lead forms and dynamically capture customer interest data.\n    \n\n#### **Environment Overview**\n\nExamples of enviromnents; the actual Base URL to be used will be shared by the integration team.\n\n| Environment | Base URL | Description |\n| --- | --- | --- |\n| **Development (dev)** | `https://dev.integration.{country}.sodtrack-shared.sodtrack.com` | Sandbox environment for testing and development. |\n| **UAT (uat)** | `https://uat.integration.{country}.sodtrack-shared.sodtrack.com` | User Acceptance Testing environment for pre-production validation. |\n| **Production (prod)** | `https://integration.{country}.sodtrack-shared.sodtrack.com` | Live production environment. All requests here affect real data. |\n\n#### **Support and Assistance**\n\nIf you require support during your integration, our technical team is available to assist with API setup, authentication, and best practices.\n\n📩 **Contact:** [integrations@sodtrack.com](https://null)",
    "contact": {
      "name": "Sodtrack API support",
      "url": "https://www.sodtrack.com/developers/tenant-api"
    }
  },
  "servers": [
    {
      "url": "https://dev.integration.cl.sodtrack-shared.sodtrack.com",
      "description": "Sandbox"
    },
    {
      "url": "https://prod.integration.cl.sodtrack-shared.sodtrack.com",
      "description": "Production (unverified)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": "Authentication is the foundation for securely interacting with the Sodtrack Integration API."
    },
    {
      "name": "Bookings",
      "description": "The bookings section is a key component of Sodtrack's flow and API."
    },
    {
      "name": "Projects"
    },
    {
      "name": "Leads"
    },
    {
      "name": "Work orders"
    },
    {
      "name": "Budgets"
    },
    {
      "name": "Product"
    },
    {
      "name": "Product Units"
    },
    {
      "name": "Acquisition"
    },
    {
      "name": "Transactions"
    },
    {
      "name": "Payment requests"
    },
    {
      "name": "Users"
    },
    {
      "name": "Incidents"
    },
    {
      "name": "Area Pricing"
    },
    {
      "name": "Attachment"
    },
    {
      "name": "Alerts"
    },
    {
      "name": "Catalog",
      "description": "This section provides all the catalog information, including available categories, services, and variants."
    },
    {
      "name": "Configuration"
    },
    {
      "name": "Coverage",
      "description": "This section includes the endpoint to verify if a specific variant has coverage in a given location."
    }
  ],
  "paths": {
    "/api/authentication/generateJWT": {
      "post": {
        "operationId": "authenticationGetToken",
        "summary": "Get token",
        "description": "Generates a JSON Web Token (JWT) that must be included in the header of all subsequent API requests to access protected resources.\n\nEach token is issued using the **API Key** and **Origin** assigned to your organization. Tokens are time-limited and must be regenerated upon expiration.\n\n### **Usage**\n\nOnce generated, include the JWT in the `Authorization` header for all API calls:\n\n```\nAuthorization: Bearer {token}\n\n```\n\n* * *\n\n### **Security Recommendations**\n\n-   🔒 Treat your **API Key** and **JWT** as sensitive credentials.\n    \n-   ⏱ Refresh tokens periodically before expiration to avoid interruptions in service.\n    \n-   ❌ Do not expose your credentials in client-side applications, browser code, or public repositories.\n    \n-   ✅ Use secure HTTPS connections at all times.",
        "tags": [
          "Authentication"
        ],
        "parameters": [
          {
            "name": "x-api-key",
            "in": "header",
            "required": false,
            "description": "string\n\nAPI Key provided by Sodtrack. This key identifies and authenticates your integration.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "description": "string\n\nThe origin domain or identifier associated with your Sodtrack API access (e.g., dev.api.cl.sodtrack.sodtrack.com).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get token response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmlnaW4iOiJkZXYuYXBpLmNsLsXdRHRyYWNrLnNvZHRyYWNrLmNvbSIsImlhdCI6MTczNjQ5MDE5OSwiZXhwIjoxNzM2NDkwNDk5fQ.21hkIFzXb1psNTqjPD8AuMq_eqeLFnzK44HT3CUXGDY"
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/booking": {
      "get": {
        "operationId": "bookingsGetBookings",
        "summary": "Get bookings",
        "description": "### **Purpose**\n\nReturns a **paginated** list of bookings enriched with related entites data for integration use cases.\n\n* * *\n\n### **Field Definitions**\n\n#### 🔐 **Authentication**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `x-api-key` (header) | `string` | ✅ | External integration API key provided by Sodtrack. |\n\n#### 🔎 **Query parameters**\n\n| Parameter | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | `number` | ❌ | Filter by Sodtrack booking id. Positive integer (minimum `1`). |\n| `reference` | `string` | ❌ | Filter by booking external reference. |\n| `pageSize` | `number` | ❌ | Number of results per page. Min `1`, max `50`. Default **`10`**. |\n| `pageNumber` | `number` | ❌ | Page index (**1-based**). Min `1`. Default **`1`**. |\n\n> All filters provided are combined with **AND**. If neither `id` nor `reference` is sent, the endpoint returns the paginated list of **all** bookings ordered by `id` descending.\n\n* * *\n\n### **Example Request**\n\n```\nGET /api/integration/booking?reference=ORD-2025-001\nGET /api/integration/booking?id=10452\nGET /api/integration/booking?pageSize=20&pageNumber=2\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": 10452,\n      \"reference\": \"ORD-2025-001\",\n      \"status\": \"accepted\",\n      \"scheduledDate\": \"2025-03-15T09:00:00.000Z\",\n      \"quantity\": 1,\n      \"totalDurationMinutes\": 90,\n      \"doneDate\": null,\n      \"createdDate\": \"2025-03-10T14:22:00.000Z\",\n      \"customer\": {\n        \"id\": 2001,\n        \"reference\": \"EXT-CUSTOMER-REF-001\"\n      },\n      \"stakeholder\": {\n        \"id\": \"stakeholder-uuid-01\",\n        \"reference\": \"STK-REF-001\"\n      },\n      \"service\": {\n        \"id\": 10,\n        \"name\": \"Instalación\"\n      },\n      \"variant\": {\n        \"id\": 321,\n        \"name\": \"Instalación cortinas\",\n        \"type\": \"execution\",\n        \"skus\": [\"install_curtains_sku\"]\n      },\n      \"category\": {\n        \"id\": 5,\n        \"name\": \"Hogar\"\n      },\n      \"address\": {\n        \"formattedAddress\": \"Av. Providencia 1234, Santiago, Chile\",\n        \"coordinates\": {\n          \"lat\": -33.43324794409109,\n          \"lng\": -70.58645659063548\n        }\n      },\n      \"originAddress\": null,\n      \"saleChannel\": {\n        \"id\": 1,\n        \"name\": \"Canal principal\",\n        \"reference\": \"E001\",\n        \"coordinates\": null\n      },\n      \"project\": {\n        \"id\": 88,\n        \"reference\": \"PROJ-EXT-100\"\n      },\n      \"lead\": null,\n      \"provider\": {\n        \"id\": 42,\n        \"reference\": \"PROV-REF-42\",\n        \"name\": \"María\",\n        \"lastname\": \"Técnica\",\n        \"email\": \"maria.tecnica@example.com\",\n        \"phone\": \"+56912345678\",\n        \"identificationNumber\": \"12345678-9\",\n        \"assignedTo\": null\n      },\n      \"bookingBundle\": null,\n      \"price\": 150000,\n      \"cost\": 80000,\n      \"bookingAddOns\": [\n        {\n          \"id\": 501,\n          \"name\": \"Material extra\",\n          \"reference\": \"ADDON-REF-01\"\n        }\n      ],\n      \"products\": [\n        {\n          \"id\": 300,\n          \"name\": \"Cortina roller\",\n          \"sku\": \"CURTAIN-001\",\n          \"productType\": \"product\",\n          \"quantity\": 2,\n          \"serialNumber\": null,\n          \"pricing\": {\n            \"price\": 45000,\n            \"cost\": 30000,\n            \"currency\": {\n              \"id\": 2,\n              \"name\": \"CLP\",\n              \"symbol\": \"$\"\n            }\n          }\n        },\n        {\n          \"id\": 415,\n          \"name\": \"Soporte de pared\",\n          \"sku\": \"BRACKET-010\",\n          \"productType\": \"component\",\n          \"quantity\": 4,\n          \"serialNumber\": null,\n          \"pricing\": {\n            \"price\": 3500,\n            \"cost\": null,\n            \"currency\": null\n          }\n        }\n      ],\n      \"incidents\": [\n        {\n          \"id\": 77,\n          \"reference\": \"INC-REF-77\"\n        }\n      ],\n      \"alerts\": [\n        {\n          \"id\": 23,\n          \"reference\": \"ALRT-E23423S2\"\n        }\n      ],\n      \"notes\": [\n        {\n          \"id\": 12,\n          \"note\": \"Cliente solicita ventana matutina.\",\n          \"reference\": null\n        }\n      ],\n      \"dynamicFormSnapshotFields\": [\n        {\n          \"id\": \"field-uuid-1\",\n          \"reference\": \"purchase_channel\",\n          \"value\": \"online\",\n          \"type\": \"text\",\n          \"snapshotId\": \"snapshot-uuid-1\"\n        }\n      ]\n    }\n  ],\n  \"metadata\": {\n    \"count\": 1,\n    \"pageNumber\": 1,\n    \"pageSize\": 10,\n    \"totalPages\": 1\n  }\n}\n\n```\n\n#### **Pagination (****`metadata`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `count` | `number` | Total number of bookings matching the filters (across all pages). |\n| `pageSize` | `number` | Page size used for this response. |\n| `pageNumber` | `number` | Current page (1-based). |\n| `totalPages` | `number` | Total pages for the current filters and `pageSize`. |\n\n#### **Booking item (****`data[]`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sodtrack booking id. |\n| `reference` | `string` | `null` |\n| `status` | `string` | Booking status. One of: `created`, `searching`, `accepted`, `on_my_way_to_origin`, `arrived_to_origin`, `on_my_way`, `on_my_way_to_destination`, `arrived_to_destination`, `left_destination`, `done`, `cancelled`, `waiting_customer_to_set_date`, `waiting_scheduling_mechanism`, `waiting_assignment_mechanism`, `waiting_provider_to_propose_date`, `waiting_customer_to_accept_proposed_date`. |\n| `scheduledDate` | `string` (ISO 8601) | `null` |\n| `quantity` | `number` | Booking quantity. |\n| `totalDurationMinutes` | `number` | `null` |\n| `doneDate` | `string` (ISO 8601) | `null` |\n| `createdDate` | `string` (ISO 8601) | Booking creation timestamp. |\n| `customer` | `object` | `null` |\n| `stakeholder` | `object` | `null` |\n| `service` | `object` | `null` |\n| `variant` | `object` | `null` |\n| `category` | `object` | `null` |\n| `address` | `object` | `null` |\n| `originAddress` | `object` | `null` |\n| `saleChannel` | `object` | `null` |\n| `project` | `object` | `null` |\n| `lead` | `object` | `null` |\n| `provider` | `object` | `null` |\n| `bookingBundle` | `object` | `null` |\n| `price` | `number` | `null` |\n| `cost` | `number` | `null` |\n| `bookingAddOns` | `array` | Add-ons on the booking (`id`, `name`, `reference`). |\n| `products` | `array` | Products and components linked to the booking, with pricing (see **Product**). |\n| `incidents` | `array` | Incident references (`id`, `reference`). |\n| `alerts` | `array` | Alert references (`id`, `reference`). |\n| `notes` | `array` | Booking notes (`id`, `note`, `reference`). |\n| `dynamicFormSnapshotFields` | `array` | Dynamic form field values captured on the booking (see **Dynamic form field**). |\n\n#### **Nested reference objects**\n\nObjects such as `customer`, `stakeholder`, `project`, `lead`, `incidents[]`, `alerts[]` and `bookingBundle.bundleHead` use:\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | `string` |\n| `reference` | `string` | `null` |\n\n#### **Variant (****`variant`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Variant id. |\n| `name` | `string` | Variant name. |\n| `type` | `string` | `\"budget\"` or `\"execution\"`. |\n| `skus` | `array[string]` | SKUs linked to the variant. |\n\n#### **Address (\\*\\*\\*\\*`address`** **/** **`originAddress`\\*\\*\\*\\*)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `formattedAddress` | `string` | Human-readable address. |\n| `coordinates` | `object` | `null` |\n\n#### **Sales channel (****`saleChannel`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sales channel id. |\n| `name` | `string` | Sales channel name. |\n| `reference` | `string` | `null` |\n| `coordinates` | `object` | `null` |\n\n#### **Provider (****`provider`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Provider id. When the assignee belongs to a company, this is the company. |\n| `reference` | `string` | `null` |\n| `name` | `string` | Provider first name. |\n| `lastname` | `string` | Provider last name. |\n| `email` | `string` | Provider email. |\n| `phone` | `string` | `null` |\n| `identificationNumber` | `string` | `null` |\n| `assignedTo` | `object` | `null` |\n\n#### **Bundle (****`bookingBundle`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `bundleHead` | `object` | Bundle head booking (`id`, `reference`). |\n| `bundledBookings` | `array` | Other bookings in the same bundle (`id`, `reference`), excluding the current one. |\n\n#### **Product (****`products[]`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Product id. |\n| `name` | `string` | Product name. |\n| `sku` | `string` | Product SKU. |\n| `productType` | `string` | `\"product\"` or `\"component\"`. |\n| `quantity` | `number` | Quantity linked to the booking. `1` per entry when the product is expanded by physical unit. |\n| `serialNumber` | `string` | `null` |\n| `pricing` | `object` | Unit pricing of the product for this booking (see **Product pricing**). |\n\n#### **Product pricing (****`products[].pricing`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `price` | `number` | `null` |\n| `cost` | `number` | `null` |\n| `currency` | `object` | `null` |\n\n#### **Dynamic form field (****`dynamicFormSnapshotFields[]`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `string` | Field instance id. |\n| `reference` | `string` | Field reference in the form definition. |\n| `value` | `string` | Submitted value. |\n| `type` | `string` | Field type. |\n| `snapshotId` | `string` | Parent snapshot id. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `id must be an integer number` / `id must not be less than 1` | `id` is not a positive integer. |\n| `400 Bad Request` | `pageSize must not be greater than 50` / `pageSize must not be less than 1` | `pageSize` out of range. |\n| `400 Bad Request` | `pageNumber must not be less than 1` | `pageNumber` out of range. |\n| `401 Unauthorized` | — | API key missing or invalid, or the request does not come from an authorized network. |\n| `403 Forbidden` | — | The request origin is not allowed. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\nWhen the filters match no booking, `data` is an empty array and `metadata.count` is `0`.\n\n* * *\n\n# Business Rules & Constraints\n\n## Filters\n\n-   `id` and `reference` are combined with **AND**. Sending both returns the booking only if it matches both values; if they point at different bookings the result is an empty page, not an error.\n    \n-   With no `id` or `reference`, the endpoint returns **all** bookings (paginated), ordered by `id` **descending** (newest first).\n    \n-   Unknown query parameters are ignored.\n    \n\n## Pagination\n\n-   `pageNumber` is **1-based** (first page = `1`).\n    \n-   Default `pageSize` is **10**; maximum allowed is **50**. Out-of-range values are rejected with `400 Bad Request`.\n    \n-   `metadata.count` is the total of matching bookings; use it with `pageSize` to iterate pages.\n    \n\n## Product pricing resolution\n\nFor each entry in `products[]`, Sodtrack resolves `pricing` as follows:\n\n| Scenario | `price` | `cost` | `currency` |\n| --- | --- | --- | --- |\n| The product (or component) has an active area pricing that covers the area of the booking address | Area pricing price | Area pricing cost (`null` if not configured) | Currency of that area |\n| No area pricing applies, and the product has a catalog price | Catalog price | `null` | `null` |\n| No area pricing applies and no catalog price is loaded | `null` | `null` | `null` |\n\n-   The area is determined from the booking `address`. A booking without an address, or whose address is not inside any area, never uses area pricing.\n    \n-   Inactive area pricing configurations and configurations without a price are ignored.\n    \n-   A catalog price of `0` is treated as \"no price loaded\" and returned as `null`.\n    \n-   Prices are per unit; multiply by `quantity` to obtain totals.\n    \n-   Products and components are priced by the same rules; the pricing configuration is looked up according to `productType`.\n    \n\n## Enriched payload\n\nEach booking in `data` is built with related data loaded. A `null` nested object means that relation is not set on the booking.\n\n## Dynamic forms included\n\nSnapshot fields are returned for every booking-related dynamic form flow configured for the booking entity and answered for that particular booking.\n\n## Data and format\n\n-   Timestamps use **ISO 8601** (UTC).\n    \n-   Query parameter values are passed as strings in the URL; `id`, `pageSize` and `pageNumber` are coerced to integers before validation.",
        "tags": [
          "Bookings"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "id must be an integer number / id must not be less than 1 — id is not a positive integer."
          },
          "401": {
            "description": "API key missing or invalid, or the request does not come from an authorized network."
          },
          "403": {
            "description": "The request origin is not allowed."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "default": {
            "description": "Get bookings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "reference": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "scheduledDate": {
                            "type": "string"
                          },
                          "totalDurationMinutes": {
                            "type": "integer"
                          },
                          "doneDate": {
                            "type": "null"
                          },
                          "createdDate": {
                            "type": "string"
                          },
                          "customer": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "reference": {
                                "type": "string"
                              }
                            }
                          },
                          "stakeholder": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "reference": {
                                "type": "string"
                              }
                            }
                          },
                          "service": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "variant": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string"
                              },
                              "skus": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "category": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "address": {
                            "type": "object",
                            "properties": {
                              "formattedAddress": {
                                "type": "string"
                              },
                              "coordinates": {
                                "type": "object",
                                "properties": {
                                  "lat": {
                                    "type": "number"
                                  },
                                  "lng": {
                                    "type": "number"
                                  }
                                }
                              }
                            }
                          },
                          "originAddress": {
                            "type": "null"
                          },
                          "saleChannel": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "reference": {
                                "type": "string"
                              },
                              "coordinates": {
                                "type": "null"
                              }
                            }
                          },
                          "project": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "reference": {
                                "type": "string"
                              }
                            }
                          },
                          "lead": {
                            "type": "null"
                          },
                          "provider": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "reference": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "lastname": {
                                "type": "string"
                              },
                              "email": {
                                "type": "string"
                              },
                              "phone": {
                                "type": "string"
                              },
                              "identificationNumber": {
                                "type": "string"
                              },
                              "assignedTo": {
                                "type": "null"
                              }
                            }
                          },
                          "bookingBundle": {
                            "type": "null"
                          },
                          "price": {
                            "type": "integer"
                          },
                          "cost": {
                            "type": "integer"
                          },
                          "bookingAddOns": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "reference": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "products": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                },
                                "productType": {
                                  "type": "string"
                                },
                                "quantity": {
                                  "type": "integer"
                                },
                                "serialNumber": {
                                  "type": "null"
                                }
                              }
                            }
                          },
                          "incidents": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "reference": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "alerts": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "reference": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "notes": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "note": {
                                  "type": "string"
                                },
                                "reference": {
                                  "type": "null"
                                }
                              }
                            }
                          },
                          "dynamicFormSnapshotFields": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "reference": {
                                  "type": "string"
                                },
                                "value": {
                                  "type": "string"
                                },
                                "type": {
                                  "type": "string"
                                },
                                "snapshotId": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "metadata": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "pageNumber": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 10452,
                      "reference": "ORD-2025-001",
                      "status": "accepted",
                      "scheduledDate": "2025-03-15T09:00:00.000Z",
                      "totalDurationMinutes": 90,
                      "doneDate": null,
                      "createdDate": "2025-03-10T14:22:00.000Z",
                      "customer": {
                        "id": 2001,
                        "reference": "EXT-CUSTOMER-REF-001"
                      },
                      "stakeholder": {
                        "id": "stakeholder-uuid-01",
                        "reference": "STK-REF-001"
                      },
                      "service": {
                        "id": 10,
                        "name": "Instalación"
                      },
                      "variant": {
                        "id": 321,
                        "name": "Instalación cortinas",
                        "type": "execution",
                        "skus": [
                          "install_curtains_sku"
                        ]
                      },
                      "category": {
                        "id": 5,
                        "name": "Hogar"
                      },
                      "address": {
                        "formattedAddress": "Av. Providencia 1234, Santiago, Chile",
                        "coordinates": {
                          "lat": -33.43324794409109,
                          "lng": -70.58645659063548
                        }
                      },
                      "originAddress": null,
                      "saleChannel": {
                        "id": 1,
                        "name": "Canal principal",
                        "reference": "E001",
                        "coordinates": null
                      },
                      "project": {
                        "id": 88,
                        "reference": "PROJ-EXT-100"
                      },
                      "lead": null,
                      "provider": {
                        "id": 42,
                        "reference": "PROV-REF-42",
                        "name": "María",
                        "lastname": "Técnica",
                        "email": "maria.tecnica@example.com",
                        "phone": "+56912345678",
                        "identificationNumber": "12345678-9",
                        "assignedTo": null
                      },
                      "bookingBundle": null,
                      "price": 150000,
                      "cost": 80000,
                      "bookingAddOns": [
                        {
                          "id": 501,
                          "name": "Material extra",
                          "reference": "ADDON-REF-01"
                        }
                      ],
                      "products": [
                        {
                          "id": 300,
                          "name": "Cortina roller",
                          "sku": "CURTAIN-001",
                          "productType": "product",
                          "quantity": 2,
                          "serialNumber": null
                        }
                      ],
                      "incidents": [
                        {
                          "id": 77,
                          "reference": "INC-REF-77"
                        }
                      ],
                      "alerts": [
                        {
                          "id": 23,
                          "reference": "ALRT-E23423S2"
                        }
                      ],
                      "notes": [
                        {
                          "id": 12,
                          "note": "Cliente solicita ventana matutina.",
                          "reference": null
                        }
                      ],
                      "dynamicFormSnapshotFields": [
                        {
                          "id": "field-uuid-1",
                          "reference": "purchase_channel",
                          "value": "online",
                          "type": "text",
                          "snapshotId": "snapshot-uuid-1"
                        }
                      ]
                    }
                  ],
                  "metadata": {
                    "count": 10452,
                    "pageSize": 1,
                    "pageNumber": 1,
                    "totalPages": 10452
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/booking/v2": {
      "post": {
        "operationId": "bookingsCreateBooking",
        "summary": "Create booking",
        "description": "### **Purpose**\n\nCreates one or more new bookings in Sodtrack.\n\nThis endpoint supports **batch creation**, allowing a single request to include multiple services in the `data` array.\n\nWhen multiple service entries are provided, Sodtrack automatically determines whether they can be **grouped** under a single provider and appointment slot.\n\nIf grouping is not possible (due to scheduling, coverage, or provider constraints), **individual ungrouped bookings** will be created.\n\nBookings can be created **in a specific project**: you can send a **project identifier** (`project`), optionally with a **shopping cart** within that project (`project.shoppingCart`), or a root-level **shopping cart id** (`shoppingCartId`) for compatibility. When `project` is present, it takes precedence and the shopping cart is resolved from the project (see **Project and shopping cart resolution** in Business Rules).\n\nEach service line can optionally include one or more **products** (`data[].products`) to associate physical items with the booking (for example, the appliance being installed or delivered). Product resolution adapts to your Sodtrack configuration and to the service variant type (see **Product resolution** in Business Rules).\n\n* * *\n\n### **Field Definitions**\n\n#### 🧍 Customer\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customer` | `object` | ✅ | Customer or requester information. |\n| `customer.name` | `string` | ✅ | Customer's first name. |\n| `customer.lastName` | `string` | ❌ | Customer's last name. |\n| `customer.identificationNumber` | `string` | ❌ | National ID or tax identification number. |\n| `customer.identificationNumberCountry` | `string` | ❌ | ISO 3166-1 alpha-2 country code for the identification number. |\n| `customer.phoneNumber` | `string` | ❌ | Contact phone number in international format. |\n| `customer.email` | `string` | ❌ | Customer's email address. |\n| `customer.reference` | `string` | ❌ | External reference of the customer. |\n\n> If customer is new, one of email, reference or identification numbers should be provided, in order to generate a temporary email for that customer\n\n* * *\n\n#### 🧍 Stakeholders\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `stakeholders` | `array[object]` | ❌ | Stakeholder who requested the booking. Only the first element is used and is applied to all created bookings. |\n| `stakeholders[].stakeholderId` | `string` | ❌ | Link to an existing Sodtrack stakeholder by id. When provided, other fields are not required. |\n| `stakeholders[].name` | `string` | ✅ when creating new | Stakeholder's first name (required when creating a new stakeholder, i.e. when `stakeholderId` is omitted). |\n| `stakeholders[].lastName` | `string` | ❌ | Stakeholder's last name. |\n| `stakeholders[].identificationNumber` | `string` | ❌ | National ID or tax identification number. |\n| `stakeholders[].identificationNumberCountry` | `string` | ❌ | ISO 3166-1 alpha-2 country code for the identification number. |\n| `stakeholders[].phoneNumber` | `string` | ❌ | Contact phone number in international format. |\n| `stakeholders[].email` | `string` | ❌ | Stakeholder's email address. |\n| `stakeholders[].reference` | `string` | ❌ | External reference of the stakeholder. |\n\n> If stakeholder is new, one of email, reference or identification number should be provided.\n\n* * *\n\n#### 🏠 **Address**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `address` | `object` | ✅ | Physical service address (destination). |\n| `address.address` | `string` | ❌ | Main address or street. Omitted only if coordinates are provided; otherwise required for geocoding. |\n| `address.extraInfo` | `string` | ❌ | Additional address details (e.g., apartment, suite number). |\n| `address.coordinate` | `object` | ❌ | Optional geographic coordinates of the service location. |\n| `address.coordinate.lat` | `number` | ❌ | Latitude. |\n| `address.coordinate.lng` | `number` | ❌ | Longitude. |\n| `address.associateToCustomer` | `boolean` | ❌ | Whether the address should be stored and associated to the customer for reuse. Defaults to **true** when omitted. |\n\n> If coordinates are not provided, Sodtrack attempts to geocode the address automatically when geo-reference is part of your subscription.  \n> If geocoding fails, the booking will be created without a map location and must be manually geolocated by an administrator before provider assignment.\n\n* * *\n\n#### 🏠 Origin address\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `originAddress` | `object` | ❌ | Origin address where the booking starts (e.g. pick-up, depot). |\n| `originAddress.address` | `string` | ❌ | Origin address or street. |\n| `originAddress.extraInfo` | `string` | ❌ | Additional address details (e.g., apartment, suite number). |\n| `originAddress.coordinate` | `object` | ❌ | Optional geographic coordinates of the origin location. |\n| `originAddress.coordinate.lat` | `number` | ❌ | Latitude. |\n| `originAddress.coordinate.lng` | `number` | ❌ | Longitude. |\n| `originAddress.associateToCustomer` | `boolean` | ❌ | Whether the origin address should be stored and associated to the customer. Defaults to **false** when omitted. |\n\n> If coordinates are not provided, Sodtrack attempts to geocode the address automatically when geo-reference is part of your subscription.  \n> If geocoding fails, the booking will be created without a map location and must be manually geolocated by an administrator before provider assignment.\n\n* * *\n\n#### 🧩 **Booking Data**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `data` | `array[object]` | ✅ | One or more service items to be booked. Each element represents a booking unit. |\n| `data[].variant` | `object` | ✅ | Defines the main service variant. |\n| `data[].variant.type` | `string` | ✅ | Type of variant identifier: `\"variantId\"` or `\"variantSku\"`. |\n| `data[].variant.value` | `string` | ✅ | Identifier corresponding to the selected variant. |\n| `data[].variant.quantity` | `number` | ✅ | Quantity of the main variant requested. |\n| `data[].variant.price` | `number` | ❌ | Price paid by the customer (for integrations that include pricing). |\n| `data[].variant.cost` | `number` | ❌ | Cost paid to the provider. |\n| `data[].addons` | `array[object]` | ❌ | Optional list of additional variants (add-ons). |\n| `data[].addons[].type` | `string` | ✅ when addon sent | Add-on identifier type: `\"addonId\"` or `\"addonReference\"`. |\n| `data[].addons[].value` | `string` | ✅ when addon sent | Add-on identifier value. |\n| `data[].addons[].quantity` | `number` | ✅ when addon sent | Quantity of the add-on. |\n| `data[].addons[].price` | `number` | ❌ | Price charged to the customer for the add-on. |\n| `data[].addons[].cost` | `number` | ❌ | Cost paid to the provider for the add-on. |\n| `data[].products` | `array[object]` | ❌ | Optional list of physical products to associate with the booking. See **Product resolution** in Business Rules. |\n| `data[].products[].type` | `string` | ✅ when product sent | Product identifier type: `\"productSku\"` or `\"productId\"`. |\n| `data[].products[].value` | `string` | ✅ when product sent | Product identifier value: the SKU string, or the product id as a **string** when `type` is `\"productId\"`. |\n| `data[].products[].quantity` | `number` | ✅ when product sent | Quantity of the product. Integer between **1** and **30**. |\n| `data[].products[].serialNumber` | `string` | ❌ | Serial number of a specific product unit. Applies only to variants linked to products, and only when `quantity` is `1`. |\n| `data[].products[].deliveryDate` | `string` (ISO 8601) | ❌ | Promised delivery date for the product. Interpreted in your instance's timezone. |\n| `data[].transport` | `object` | ❌ | Optional transport-related charges. |\n| `data[].transport.price` | `number` | ❌ | Price charged to the customer. |\n| `data[].transport.cost` | `number` | ❌ | Cost allocated to the provider. |\n| `data[].dynamicForms` | `array[object]` | ❌ | Optional form data collected as part of the booking (if configured in Sodtrack). |\n| `data[].dynamicForms[].formReference` | `string` | ✅ when form sent | Form reference identifier. |\n| `data[].dynamicForms[].values` | `object` | ✅ when form sent | Key-value map of submitted field data. |\n\nWhen multiple items are included in the `data` array (`length > 1`), Sodtrack automatically determines whether they can be grouped under a single booking (same provider/date).\n\nIf grouping is not possible, individual bookings are created for each service item.\n\n* * *\n\n#### 🕒 **Date Assignment**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `dateAssignment` | `object` | ❌ | Defines how the booking date is determined. See **Date assignment** in Business Rules. |\n| `dateAssignment.type` | `string` | ✅ when object sent | One of: `\"direct\"`, `\"user_scheduling\"`, `\"userScheduling\"`, `\"onDemand\"`, `\"providerScheduling\"`. |\n| `dateAssignment.date` | `string` (ISO 8601) | ❌ | Date and time for the booking. Required for scheduling when `type` is `\"direct\"`. |\n| `dateAssignment.timeRange` | `object` | ❌ | Time range within the day (used with `type = \"direct\"` when applicable). |\n| `dateAssignment.timeRange.type` | `string` | ✅ when timeRange sent | `\"timeRangeId\"` or `\"timeRangeIndex\"`. |\n| `dateAssignment.timeRange.value` | `number` | ✅ when timeRange sent | Identifier or index of the time range. |\n\n* * *\n\n#### 👷 **Provider Assignment**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `providerAssignment` | `object` | ❌ | Defines how the provider or technician is assigned. See **Booking or bundle scheduling logic** in Business Rules. |\n| `providerAssignment.type` | `string` | ✅ when object sent | `\"automatic\"` or `\"direct\"`. |\n| `providerAssignment.provider` | `object` | ❌ | Required when `type` is `\"direct\"`. Specifies the provider when manually assigned. |\n| `providerAssignment.provider.type` | `string` | ✅ when provider sent | `\"providerId\"` or `\"providerReference\"`. |\n| `providerAssignment.provider.value` | `string` | ✅ when provider sent | ID or external reference of the provider. |\n\n* * *\n\n#### 📣 **Sales channel**\n\nIdentifies which **sales / integration channel** the bookings belong to. The channel must exist and be configured in Sodtrack.\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `saleChannel` | `object` | ✅ | Identifies the channel by reference or by internal id. See nested fields below. |\n| `saleChannel.type` | `string` | ✅ when `saleChannel` sent | One of: `\"reference\"` (lookup by channel reference, e.g. `E001`) or `\"id\"` (lookup by Sodtrack numeric id). |\n| `saleChannel.value` | `string` | ✅ when `saleChannel` sent | Value for the chosen type: the channel **reference** string, or the channel **id** as a **string** (e.g. `\"1\"`). For `type: \"id\"`, the value must be a **positive integer** as string (decimals are rejected). |\n\n* * *\n\n#### 📁 **Project** (optional)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `project` | `object` | ❌ | Project where the bookings will be created. When provided, Sodtrack resolves the project and then the shopping cart (see **Project and shopping cart resolution**). Takes precedence over root-level `shoppingCartId` when both are sent. |\n| `project.type` | `string` | ✅ when project sent | Type of project identifier: `\"projectId\"` or `\"projectReference\"`. |\n| `project.value` | `string` | ✅ when project sent | Internal Sodtrack project ID, or external reference of the project. |\n| `project.shoppingCart` | `object` | ❌ | Optional. Target a specific shopping cart within the project (by ID or reference). When omitted, the latest shopping cart of the project is used, or a new one is created. |\n| `project.shoppingCart.type` | `string` | ✅ when shoppingCart sent | How the cart is identified: `\"shoppingCartId\"` or `\"shoppingCartReference\"`. |\n| `project.shoppingCart.value` | `string` | ✅ when shoppingCart sent | Shopping cart ID (numeric as string) or external reference of the cart within the project. |\n\n* * *\n\n#### 🧾 **Additional Metadata**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `reference` | `string` | ❌ | External system reference (e.g., order ID). |\n| `createPaymentTransaction` | `boolean` | ❌ | If **true**, creates a payment transaction for each created booking. |\n| `useStrictCoverageValidationMode` | `boolean` | ❌ | **true**: all-or-nothing validation (default). **false**: best-effort mode; only valid bookings are created. See Coverage Validation Behavior. |\n\n* * *\n\n### **Example Request (with project)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"María\",\n    \"lastName\": \"García\",\n    \"identificationNumber\": \"12345678-9\",\n    \"identificationNumberCountry\": \"CL\",\n    \"phoneNumber\": \"+56912345678\",\n    \"email\": \"maria.garcia@example.com\"\n  },\n  \"address\": {\n    \"address\": \"Av. Providencia 1234, Santiago\",\n    \"extraInfo\": \"Depto 501\",\n    \"coordinate\": {\n      \"lat\": -33.43324794409109,\n      \"lng\": -70.58645659063548\n    }\n  },\n  \"data\": [\n    {\n      \"variant\": {\n        \"type\": \"variantSku\",\n        \"value\": \"install_curtains_sku\",\n        \"quantity\": 2,\n        \"price\": 150000,\n        \"cost\": 80000\n      }\n    }\n  ],\n  \"dateAssignment\": {\n    \"type\": \"direct\",\n    \"date\": \"2025-03-15T09:00:00.000Z\"\n  },\n  \"providerAssignment\": {\n    \"type\": \"direct\",\n    \"provider\": {\n      \"type\": \"providerId\",\n      \"value\": \"42\"\n    }\n  },\n  \"reference\": \"ORD-2025-001\",\n  \"saleChannel\": {\n    \"type\": \"id\",\n    \"value\": \"1\"\n  },\n  \"project\": {\n    \"type\": \"projectReference\",\n    \"value\": \"PROJ-EXT-100\"\n  },\n  \"useStrictCoverageValidationMode\": true\n}\n\n```\n\n### **Example Request (with project and specific shopping cart)**\n\n```json\n{\n  \"customer\": { \"name\": \"María\", \"lastName\": \"García\", \"email\": \"maria@example.com\" },\n  \"address\": { \"address\": \"Av. Providencia 1234, Santiago\", \"coordinate\": { \"lat\": -33.43, \"lng\": -70.58 } },\n  \"data\": [{ \"variant\": { \"type\": \"variantSku\", \"value\": \"install_curtains_sku\", \"quantity\": 1 } }],\n  \"saleChannel\": {\n    \"type\": \"id\",\n    \"value\": \"1\"\n  },\n  \"project\": {\n    \"type\": \"projectReference\",\n    \"value\": \"PROJ-EXT-100\",\n    \"shoppingCart\": {\n      \"type\": \"shoppingCartReference\",\n      \"value\": \"STAGE-ORDER-2025-001\"\n    }\n  }\n}\n\n```\n\nWhen no cart exists in the project with reference `STAGE-ORDER-2025-001`, Sodtrack creates a new shopping cart with that reference and attaches the bookings to it.\n\n### **Example Request (minimal)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"Juan Pérez\"\n  },\n  \"address\": {\n    \"address\": \"Calle Principal 100, Ciudad\"\n  },\n  \"data\": [\n    {\n      \"variant\": {\n        \"type\": \"variantId\",\n        \"value\": \"321\",\n        \"quantity\": 1\n      }\n    }\n  ],\n  \"saleChannel\": {\n    \"type\": \"id\",\n    \"value\": \"1\"\n  },\n}\n\n```\n\n* * *\n\n### **Example Request (minimal with saleChannel by reference)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"Juan Pérez\"\n  },\n  \"address\": {\n    \"address\": \"Calle Principal 100, Ciudad\"\n  },\n  \"data\": [\n    {\n      \"variant\": {\n        \"type\": \"variantId\",\n        \"value\": \"321\",\n        \"quantity\": 1\n      }\n    }\n  ],\n  \"saleChannel\": {\n    \"type\": \"reference\",\n    \"value\": \"ref1\"\n  },\n}\n\n```\n\n### **Example Request (with products)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"María\",\n    \"lastName\": \"García\",\n    \"email\": \"maria.garcia@example.com\"\n  },\n  \"address\": {\n    \"address\": \"Av. Providencia 1234, Santiago\"\n  },\n  \"data\": [\n    {\n      \"variant\": {\n        \"type\": \"variantSku\",\n        \"value\": \"install_appliance_sku\",\n        \"quantity\": 1\n      },\n      \"products\": [\n        {\n          \"type\": \"productSku\",\n          \"value\": \"WASHER-XYZ-500\",\n          \"quantity\": 1,\n          \"serialNumber\": \"SN-998877\",\n          \"deliveryDate\": \"2026-03-15\"\n        }\n      ]\n    }\n  ],\n  \"saleChannel\": {\n    \"type\": \"id\",\n    \"value\": \"1\"\n  }\n}\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"bookings\": [\n    {\n      \"id\": 10452,\n      \"quantity\": 2,\n      \"variantSku\": [\"install_curtains_sku\"],\n      \"variantId\": 321\n    }\n  ]\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `bookings` | `array[object]` | List of created bookings. |\n| `bookings[].id` | `number` | Unique Sodtrack booking ID. |\n| `bookings[].quantity` | `number` | Quantity of services booked. |\n| `bookings[].variantSku` | `array[string]` | List of variant SKUs associated with the booking. |\n| `bookings[].variantId` | `number` | Internal variant identifier. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid. |\n| `400 Bad Request` | `INVALID_SALES_CHANNEL` | The given `saleChannel` was not found (in strict mode). |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `404 Not Found` | — | A referenced variant, provider, project, or channel could not be found. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Project and shopping cart resolution\n\nYou can target a **project** and optionally a **shopping cart** within it, or use a root-level **shopping cart id** for compatibility.\n\n-   **`project`** (without `project.shoppingCart`): Send a project identifier (`projectId` or `projectReference`). Sodtrack resolves the project and then uses the **latest shopping cart** linked to that project. If the project has no shopping cart, a **new shopping cart** is created for that project and the bookings are attached to it.\n-   **`project`** with **`project.shoppingCart`**: In addition to the project, you can target a specific cart within that project:\n    -   **`type = \"shoppingCartId\"`**: Sodtrack looks up the shopping cart by project and cart ID. If no cart is found with that ID in the project, it **falls back** to the latest shopping cart of the project.\n    -   **`type = \"shoppingCartReference\"`**: Sodtrack looks up the shopping cart by project and cart reference. If no cart is found with that reference, it **creates a new shopping cart** for the project with the given reference (and uses it for the bookings). The new cart’s stage name is derived from the project name and the reference.\n\nWhen `project` is not sent, Sodtrack creates the bookings without attaching them to a project; further behavior depends on your configuration.\n\n* * *\n\n## Date assignment\n\nWhen **`dateAssignment`** is sent, `type` determines how the booking date is handled. Scheduling (assigning date and provider) only runs when both `dateAssignment` and `providerAssignment` are present and the system can complete the assignment (see **Booking or bundle scheduling logic**).\n\n-   **`direct`**: The booking is scheduled to a specific date and time. **`date`** is required when scheduling is performed (ISO 8601). Optionally, **`timeRange`** can be sent to specify a time slot within the day by `timeRangeId` or `timeRangeIndex`. If `date` is missing when the system attempts to schedule, the scheduling step is skipped and the information is stored in a note on the booking.\n-   **`userScheduling`**: The user will choose the date later (e.g. via web or app). No immediate date is assigned. `userScheduling` is the preferred value; **`date`** and **`timeRange`** are not used for scheduling when this type is set.\n-   **`onDemand`**: The service is on-demand; date assignment is handled accordingly by the platform. **`date`** and **`timeRange`** are not used for direct scheduling.\n-   **`providerScheduling`**: The provider will determine or propose the date to the client. No immediate date is assigned from the request. **`date`** and **`timeRange`** are not used for direct scheduling.\n\nWhen date definition cannot be completed (e.g. address not geo-referenced, or provider assignment missing/failed), Sodtrack still creates the bookings and stores the scheduling information in a note so it is not lost.\n\n* * *\n\n## Address resolution process\n\nIf no valid coordinates are available for `address`, and for `originAddress` when provided, bookings remain unassigned until manually updated.\n\nProvided addresses go through a resolution process to determine coordinates depending on the `associateToCustomer` value and whether the geo-reference intent is part of your subscription.\n\n#### When geo-reference intent is not part of your subscription:\n\nThe system does not call the partner geocoding API. Addresses are used as provided; coordinates remain unchanged. Bookings that require coverage validation follow the non-georeferenced flow (see Strict mode / Best effort mode).\n\n#### When geo-reference intent is part of your subscription:\n\nIf no coordinates are provided for the address, the system uses the `address` attribute of the provided address object and requests a match with coordinates from a partner API.\n\n-   If exactly one match is returned, the system uses those coordinates for all subsequent validation steps, including the `associateToCustomer` = true step.\n-   If no match is returned or the partner API errors, the address remains without coordinates; resolution does not retry and the request continues with the unresolved address.\n\n#### When `associateToCustomer` = true:\n\nIf the provided customer already exists, the platform attempts to find an existing address for that customer and reuse it. Address matching requires **exact match of** **`extraInfo`** (after normalization: trim, null/undefined treated as empty) **and** at least one of the following:\n\n-   The `address` attribute of the provided address equals the existing address's address.\n-   The provided `coordinates` are within a 3 meter radius of the existing address's coordinates.\n\nIf a matching existing address is found, its coordinates and address fields are used for coverage and validations. If not, the address is created or updated as provided (and optionally geocoded when geo-reference intent is enabled).\n\n#### Defaults for address association:\n\n-   Destination address: `associateToCustomer` defaults to **true** when omitted.\n-   Origin address: `associateToCustomer` defaults to **false** when omitted.\n\n* * *\n\n## Booking bundling logic\n\nWhen the bundling capability is part of your subscription and multiple bookings are created in a single request, Sodtrack validates and creates a single bundle when possible. Bundling is **all-or-nothing**: the criteria must be satisfied for **all** created bookings in the request for a bundle to be created.\n\nBundling validation rules:\n\n-   The provided `address` has coordinates after the address resolution process.\n-   At least one technician is correctly configured to execute all bookings at that `address`.\n\nIf bundle creation fails (e.g. validation or provider constraints) bookings are still created and returned, and scheduling or note creation still runs.\n\n* * *\n\n## Product resolution\n\nEach service line (`data[]`) can include a `products` array to associate physical products with the booking. How each product is resolved depends on your Sodtrack configuration and on the service variant type.\n\n### Where products are resolved\n\n-   **When the product module is part of your subscription:** products are resolved against the product module (inventory) by SKU or product id.\n-   **Otherwise:** products are resolved against your Sodtrack product catalog by SKU or product id.\n\n### Variants that track individual units\n\nSome service variants are configured to track individual product units (units identified by a serial number). For these variants:\n\n-   The **product module must be part of your subscription**; otherwise the request is rejected with `400 Bad Request`.\n-   `serialNumber` may be provided to link a specific unit, and only when `quantity` is `1`. Sending `serialNumber` with `quantity` greater than `1` is rejected with `400 Bad Request`.\n-   When `quantity` is greater than `1`, Sodtrack creates **one booking per unit**.\n-   The same `serialNumber` cannot be repeated within a single line's `products`.\n\n### Resolution outcomes\n\n| Scenario | Behavior |\n| --- | --- |\n| Product found (variant without unit tracking) | The product is attached to the booking, together with its `deliveryDate` when provided. |\n| Product not found (variant without unit tracking) | The booking is still created; a note with the product details is added for manual handling. |\n| Product not found (unit-tracking variant) | The request is rejected with `400 Bad Request`. |\n| `serialNumber` provided and found | The specific product unit is linked to the booking. |\n| `serialNumber` provided but not found | The booking is created without the unit; a note is added so the unit can be linked later. |\n| Invalid `deliveryDate` | The request is rejected with `400 Bad Request`. |\n\n> Note creation for unresolved products is independent of `useStrictCoverageValidationMode`: for variants without unit tracking, an unresolved product never aborts the request; the booking is created and the product information is preserved in a note.\n\n### Delivery date\n\n`deliveryDate` is optional. When provided, it is interpreted using your Sodtrack instance's timezone and stored as the product's promised delivery date. An unparseable date rejects the request with `400 Bad Request`.\n\n* * *\n\n## Booking or bundle scheduling logic\n\nScheduling a booking (or the head of a bundle) requires **both** `dateAssignment` and `providerAssignment` in the request when the system is able to assign date and provider (see below).\n\nWhen the date definition for a booking or bundle cannot be completed or fails, and `dateAssignment` was provided, Sodtrack creates a **note** on that booking with the scheduling information so it is not lost. This happens when:\n\n-   `providerAssignment` is missing.\n-   `providerAssignment` was provided but date/provider assignment fails (e.g. no availability for the given technician).\n-   The destination `address` is not geo-referenced (no coordinates after resolution).\n-   `originAddress` is provided and is not geo-referenced (no coordinates after resolution).\n\nIn all of the above cases, **bookings are already created**; only the assignment step is skipped and replaced by the note.\n\n* * *\n\n## Coverage Validation Behavior\n\nThe behavior of the booking creation flow depends on two factors:\n\n1.  Whether the required addresses were successfully resolved with coordinates.\n2.  The configured mode (`useStrictCoverageValidationMode`).\n\n* * *\n\n### 1\\. When Coordinates Are NOT Resolved\n\nIf a required address (destination and/or origin, depending on the variant rules) is **not resolved with coordinates**:\n\n-   **Coverage validations are not executed.**\n-   Bookings are still created.\n-   These bookings are expected to be managed later through the web administrator.\n\nThis behavior is the same in both **Strict** and **Best Effort** modes.  \nThe selected mode does **not** affect this scenario.\n\n> Bookings created without address coordinates will require manual resolution and add operational overhead for each case.\n\n* * *\n\n### 2\\. When Coordinates ARE Resolved\n\nIf the required addresses are successfully resolved with coordinates, full validation is executed (variant existence, operation areas, coverage by destination/origin when required, addons, etc.).\n\nAt this point, the behavior depends on the selected mode.\n\n* * *\n\n#### Strict Mode\n\n`useStrictCoverageValidationMode: true` (default)\n\n-   **All-or-nothing behavior.**\n-   If any validation fails (for example, no coverage for a georeferenced address):\n    -   **No bookings are created.**\n    -   The request returns a 400 error.\n-   No partial creation is allowed.\n\nThis mode guarantees that:\n\n-   All requested variants exist.\n-   All variants have an operation area.\n-   Georeferenced addresses have coverage when required.\n-   Addons are valid, applicable and have coverage.\n\nIf any of these conditions fail, the entire request is rejected.\n\n> This mode mirrors the creation through the administrator web UI, preventing the creation of bookings that could not be satisfied with the current state of configurations.\n\n* * *\n\n#### Best Effort Mode\n\n`useStrictCoverageValidationMode: false`\n\n-   **Partial success is allowed.**\n-   Validation and coverage checks are executed, but failures do not abort the entire request.\n\nWhen coordinates are resolved:\n\n-   If a variant does not exist → it is skipped.\n-   If a variant has no operation area → it is skipped.\n-   If a variant has no coverage → that booking may be skipped.\n-   If an addon does not exist or has no coverage → it is not added to the booking.\n-   The process continues with all other valid lines.\n\nOnly successfully created bookings are returned in the response.\n\n> This mode allows the consumer to create as many valid bookings and their addons as possible, even if there is no coverage and operational overhead will be needed to handle some cases.\n\n* * *\n\n### Conceptual Summary\n\n| Coordinates Resolved? | Strict Mode | Best Effort Mode |\n| --- | --- | --- |\n| ❌ No | Bookings are created without coverage validation | Bookings are created without coverage validation |\n| ✅ Yes | If any validation fails, nothing is created | Only valid bookings are created |\n\n* * *\n\n## Stakeholder\n\n-   Optional `stakeholders` array; only the **first element** is used and is applied to **all** created bookings.\n-   **Link existing:** If `stakeholderId` is provided, Sodtrack resolves it. If the stakeholder is not found, an error is logged and no stakeholder is set on the bookings; the request is not aborted (strict and best effort).\n-   **Create new:** If `stakeholderId` is omitted but identifying data (e.g. `name`) is provided, a new stakeholder is created and its ID is used for all created bookings.\n\n* * *\n\n## Data and format\n\n-   Dynamic form data is stored and linked to each booking for later retrieval.\n-   All timestamps follow the ISO 8601 format (UTC).",
        "tags": [
          "Bookings"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Create booking",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "bookings": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "quantity": {
                            "type": "integer"
                          },
                          "variantId": {
                            "type": "integer"
                          },
                          "variantSku": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "bookings": [
                    {
                      "id": 302,
                      "quantity": 1,
                      "variantId": 2,
                      "variantSku": [
                        "8472"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "InvalidParameters — One or more required fields are missing or invalid."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "404": {
            "description": "A referenced variant, provider, project, or channel could not be found."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/booking/{bookingId}/reference": {
      "patch": {
        "operationId": "bookingsUpdateReference",
        "summary": "Update reference",
        "tags": [
          "Bookings"
        ],
        "parameters": [
          {
            "name": "bookingId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reference": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "reference": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update reference"
          }
        }
      }
    },
    "/api/integration/booking/cancel": {
      "patch": {
        "operationId": "bookingsCancelBooking",
        "summary": "Cancel Booking",
        "description": "## General Description\n\nThis endpoint cancels an existing booking through the Integration API. The booking is identified in the request body by either booking ID or booking reference.\n\nThe endpoint optionally accepts dynamic form answers, for forms associated to the booking cancellation flow.\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationCancelBookingRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `booking` | ExternalIntegrationBookingIdentifierRequestDTO | Yes | Booking identifier object. Supports lookup by booking ID or booking reference. |\n| `dynamicForms` | CreateDynamicFormSnapshotFromExternalIntegrationRequestDTO\\[\\] | No | Optional list of dynamic form answers to store as booking dynamic form snapshots on cancellation flow. |\n\n### ExternalIntegrationBookingIdentifierRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Type of booking identifier. Must be one of: `bookingId` or `bookingReference`. |\n| `value` | string | Yes | The booking ID (if type is `bookingId`) or booking reference (if type is `bookingReference`). |\n\n### CreateDynamicFormSnapshotFromExternalIntegrationRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `formReference` | string | Yes | Dynamic form reference configured in Sodtrack. |\n| `values` | CreateBookingDynamicFormFieldValueV2RequestDTO\\[\\] | Yes | List of dynamic field answers for the form. |\n\n### CreateBookingDynamicFormFieldValueV2RequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `fieldReference` | string | Yes | Dynamic form field reference to answer. |\n| `value` | string | Yes | Value to persist for the selected field. |\n\n### Success Response\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| \\- | \\- | \\- | `200 OK`. Response body is the cancelled booking (BookingDTO). |\n\n* * *\n\n## Business Rules & Constraints\n\n-   The booking must exist (`bookingId` or `bookingReference` lookup). If not found, the endpoint returns `BOOKING_NOT_FOUND_FOR_ID` (when identifying by ID) or `BOOKING_NOT_FOUND_FOR_REFERENCE` (when identifying by reference).\n    \n-   When identifying by `bookingReference`, the reference must resolve to exactly one booking. If multiple bookings share the same reference, the endpoint returns `MULTIPLE_BOOKINGS_FOUND_FOR_REFERENCE`.\n    \n-   When identifying by `bookingId`, the value must be a valid numeric ID. Invalid values return `INVALID_BOOKING_ID`.\n    \n-   The booking must be in a cancellable status. Bookings in any of the following statuses cannot be cancelled: `ON_MY_WAY_TO_ORIGIN`, `ARRIVED_TO_ORIGIN`, `ON_MY_WAY`, `ARRIVED_TO_DESTINATION`, `DONE`, `CANCELLED`. If the booking is in one of these statuses, the endpoint returns `400 Bad Request` with message \"Booking cannot be cancelled\".\n    \n-   `dynamicForms` is optional, and need an actual dynamic form configured in the platform. The dynamic form has to be associated to the booking cancellation flow and must to have references, at form and fields level, for each of the fields sent in the payload.\n    \n\n* * *\n\n## Example Request\n\n```json\n{\n  \"booking\": {\n    \"type\": \"bookingReference\",\n    \"value\": \"BOOK-EXT-789\"\n  },\n  \"dynamicForms\": [\n    {\n      \"formReference\": \"booking-cancel-reasons-v1\",\n      \"values\": [\n        {\n          \"fieldReference\": \"cancel_reason\",\n          \"value\": \"customer_request\"\n        },\n        {\n          \"fieldReference\": \"cancel_details\",\n          \"value\": \"Customer requested cancellation via external system.\"\n        }\n      ]\n    }\n  ]\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n```\n\n## Example Error Responses\n\n**Booking not found (by ID):**\n\n```json\n{\n  \"statusCode\": 404,\n  \"message\": \"BOOKING_NOT_FOUND_FOR_ID\",\n  \"error\": \"Not Found\"\n}\n\n```\n\n**Booking not found (by reference):**\n\n```json\n{\n  \"statusCode\": 404,\n  \"message\": \"BOOKING_NOT_FOUND_FOR_REFERENCE\",\n  \"error\": \"Not Found\"\n}\n\n```\n\n**Multiple bookings for same reference:**\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"MULTIPLE_BOOKINGS_FOUND_FOR_REFERENCE\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n**Invalid booking ID (non-numeric):**\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"INVALID_BOOKING_ID\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n**Booking cannot be cancelled (status not allowed):**\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"Booking cannot be cancelled\",\n  \"error\": \"Bad Request\"\n}\n\n```",
        "tags": [
          "Bookings"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancel Booking"
          }
        }
      }
    },
    "/api/integration/booking/{bookingId}/reschedule": {
      "patch": {
        "operationId": "bookingsRescheduleBooking",
        "summary": "Reschedule Booking",
        "description": "### **Purpose**\n\nGives an **existing booking a new date**, identified by its Sodtrack id.\n\nThe request carries the same `dateAssignment` object used when creating bookings, with the same meaning for each `type`: `direct` schedules the booking to a specific date and time, `userScheduling` removes the date and hands the choice back to the customer, `providerScheduling` removes the date and asks the provider to propose one, and `onDemand` turns the booking into an on-demand service to be executed as soon as possible.\n\n**This endpoint does not validate coverage or agenda availability.** It writes the date as sent. Verify beforehand that the booking's address is covered and that the provider has the requested slot, using the coverage and availability endpoints, so that this call stays cheap and predictable.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | Sodtrack inbound integration API key. |\n\nThe endpoint is restricted to Sodtrack's private integration network. Requests from unauthorized origins are rejected.\n\n* * *\n\n### **Endpoint**\n\n`PATCH /api/integration/booking/{bookingId}/reschedule`\n\n* * *\n\n### **Field Definitions**\n\n#### 🧩 **Path parameters**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `bookingId` | `number` | ✅ | Sodtrack booking id. Must be an integer. |\n\n#### 🕒 **Date assignment** (`dateAssignment`)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `dateAssignment` | `object` | ✅ | The new scheduling. Same shape as in booking creation. |\n| `dateAssignment.type` | `string` | ✅ | One of: `\"direct\"`, `\"userScheduling\"`, `\"providerScheduling\"`, `\"onDemand\"`. |\n| `dateAssignment.date` | `string (datetime)` | ✅ when type is `\"direct\"` | New date and time of the booking, ISO 8601 with timezone (for example `2026-10-15T09:00:00.000Z` or `2026-10-15T06:00:00-03:00`). With an offset or `Z` the instant is kept exactly; a value without timezone is read in your account's default timezone. Ignored for the other types. |\n| `dateAssignment.timeRange` | `object` | ❌ | Only with `\"direct\"`. Time slot to record on the booking as its period window. Does not change the time of day, which always comes from `date`. |\n| `dateAssignment.timeRange.type` | `string` | ✅ when object sent | One of: `\"timeRangeId\"`, `\"timeRangeIndex\"`. |\n| `dateAssignment.timeRange.value` | `number` | ✅ when object sent | The time range id, or its 0-based position in the list of time ranges ordered by start time. An unknown id or an index past the last range is rejected. |\n\n* * *\n\n### **Example Request**\n\nReschedule to a specific date and time:\n\n```json\n{\n  \"dateAssignment\": {\n    \"type\": \"direct\",\n    \"date\": \"2026-10-15T09:00:00.000Z\"\n  }\n}\n```\n\nHand the date back to the customer:\n\n```json\n{\n  \"dateAssignment\": {\n    \"type\": \"userScheduling\"\n  }\n}\n```\n\nTurn the booking into an on-demand service:\n\n```json\n{\n  \"dateAssignment\": {\n    \"type\": \"onDemand\"\n  }\n}\n```\n\nAsk the provider to propose a date:\n\n```json\n{\n  \"dateAssignment\": {\n    \"type\": \"providerScheduling\"\n  }\n}\n```\n\nReschedule to a date within a time range:\n\n```json\n{\n  \"dateAssignment\": {\n    \"type\": \"direct\",\n    \"date\": \"2026-10-15T09:00:00.000Z\",\n    \"timeRange\": {\n      \"type\": \"timeRangeId\",\n      \"value\": 5\n    }\n  }\n}\n```\n\n### **Response Example**\n\nThe updated booking, in the same shape as the booking search and detail endpoints.\n\n```json\n{\n  \"id\": 13,\n  \"reference\": \"BK-2026-0456\",\n  \"status\": \"accepted\",\n  \"scheduledDate\": \"2026-10-15T09:00:00.000Z\",\n  \"quantity\": 1,\n  \"totalDurationMinutes\": 60,\n  \"doneDate\": null,\n  \"createdDate\": \"2026-08-26T04:22:29.911Z\",\n  \"customer\": {\n    \"id\": 32841,\n    \"reference\": \"CUST-00123\"\n  },\n  \"stakeholder\": null,\n  \"service\": {\n    \"id\": 1,\n    \"name\": \"Water heater installation\"\n  },\n  \"variant\": {\n    \"id\": 1,\n    \"name\": \"Standard installation\",\n    \"type\": \"execution\",\n    \"skus\": []\n  },\n  \"category\": {\n    \"id\": 1,\n    \"name\": \"Installations\"\n  },\n  \"address\": {\n    \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n    \"coordinates\": null\n  },\n  \"originAddress\": null,\n  \"saleChannel\": null,\n  \"project\": null,\n  \"lead\": null,\n  \"provider\": {\n    \"id\": 19,\n    \"reference\": null,\n    \"name\": \"Carlos\",\n    \"lastname\": \"Muñoz\",\n    \"email\": \"carlos.munoz@example.com\",\n    \"phone\": \"+56972345678\",\n    \"identificationNumber\": null,\n    \"assignedTo\": null\n  },\n  \"bookingBundle\": null,\n  \"price\": 0,\n  \"cost\": 0,\n  \"bookingAddOns\": [],\n  \"products\": [],\n  \"incidents\": [],\n  \"alerts\": [],\n  \"notes\": [],\n  \"dynamicFormSnapshotFields\": []\n}\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sodtrack booking id. |\n| `reference` | `string | null` | Your reference for the booking. |\n| `status` | `string` | Booking status after the reschedule. One of: `\"created\"`, `\"searching\"`, `\"accepted\"`, `\"on_my_way_to_origin\"`, `\"arrived_to_origin\"`, `\"on_my_way_to_destination\"`, `\"arrived_to_destination\"`, `\"left_destination\"`, `\"done\"`, `\"cancelled\"`, `\"waiting_customer_to_set_date\"`, `\"waiting_scheduling_mechanism\"`, `\"waiting_assignment_mechanism\"`, `\"waiting_provider_to_propose_date\"`, `\"waiting_customer_to_accept_proposed_date\"`. |\n| `scheduledDate` | `string (datetime) | null` | The new scheduled date. |\n| `quantity` | `number` | Quantity booked. |\n| `totalDurationMinutes` | `number | null` | Total duration in minutes. |\n| `doneDate` | `string (datetime) | null` | When the booking was completed. |\n| `createdDate` | `string (datetime)` | When the booking was created. |\n| `customer` | `object | null` | `id` and `reference` of the customer. |\n| `stakeholder` | `object | null` | `id` and `reference` of the requesting party, when different from the customer. |\n| `service` | `object | null` | `id` and `name` of the service. |\n| `variant` | `object | null` | Service variant: `id`, `name`, `type` (`\"budget\"` or `\"execution\"`) and `skus`. |\n| `category` | `object | null` | `id` and `name` of the service category. |\n| `address` | `object | null` | Execution address: `formattedAddress` and `coordinates` (`lat`, `lng`, or `null`). |\n| `originAddress` | `object | null` | Origin address for transport services. Same shape as `address`. |\n| `saleChannel` | `object | null` | Sale channel: `id`, `name`, `reference` and `coordinates`. |\n| `project` | `object | null` | `id` and `reference` of the project the booking belongs to. |\n| `lead` | `object | null` | `id` and `reference` of the originating lead. |\n| `provider` | `object | null` | Assigned provider: `id`, `reference`, `name`, `lastname`, `email`, `phone`, `identificationNumber` and `assignedTo` (`name`, `lastname`, `email` of the executing technician when the provider is a network, otherwise `null`). `null` while unassigned. |\n| `bookingBundle` | `object | null` | When the booking is part of a bundle: `bundleHead` and `bundledBookings[]`, each with `id` and `reference`. |\n| `price` | `number | null` | Booking price. |\n| `cost` | `number | null` | Booking cost. |\n| `bookingAddOns[]` | `array` | Add-ons: `id`, `name`, `reference`. |\n| `products[]` | `array` | Products in the booking: `id`, `name`, `sku`, `productType`, `quantity`, `serialNumber` and `pricing`. |\n| `incidents[]` | `array` | Incidents: `id` and `reference`. |\n| `alerts[]` | `array` | Alerts: `id` and `reference`. |\n| `notes[]` | `array` | Notes: `id`, `note`, `reference`. |\n| `dynamicFormSnapshotFields[]` | `array` | Dynamic form answers captured during the booking: `id`, `reference`, `value`, `secondaryValue`, `type`, `snapshotId`. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `Validation failed (numeric string is expected)` | `bookingId` is not an integer. |\n| `400 Bad Request` | — | `dateAssignment` is missing or malformed (`type` not one of the accepted values, `timeRange` without `type` or numeric `value`). |\n| `400 Bad Request` | `Date is required when type is DIRECT` | `dateAssignment.date` is missing. |\n| `400 Bad Request` | `INVALID_DATE: expected ISO 8601` | `dateAssignment.date` is not a valid ISO 8601 date. |\n| `400 Bad Request` | `TIME_RANGE_NOT_FOUND: {type} {value}` | No time range matches the id or index sent. |\n| `400 Bad Request` | `BOOKING_CANNOT_BE_RESCHEDULED: status {status}` | The booking is in execution, done or cancelled. |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`, or the request does not come from an authorized origin. |\n| `404 Not Found` | `BOOKING_NOT_FOUND: {bookingId}` | No booking exists with that id. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## No coverage or availability validation\n\nSodtrack does not check that the booking address is covered, nor that the assigned provider is available at the requested date, time or time range. The date is written as sent. Run those checks first with the coverage and availability endpoints; this endpoint is meant to be the final, cheap write once a valid slot is known.\n\n## What each type does\n\n| `type` | Effect on the booking |\n| --- | --- |\n| `direct` | Sets the date and time sent (and the period window when `timeRange` is given). |\n| `userScheduling` | Clears the date and any period window and marks the booking as customer-managed: the customer picks the date later from the web or the app. No effect if the booking is already customer-managed. |\n| `providerScheduling` | Clears the date and any period window and asks the assigned provider to propose a date. No effect if the booking is already waiting for a provider proposal. |\n| `onDemand` | Clears the date and any period window and marks the booking as on demand. With automatic provider assignment, Sodtrack starts searching a provider right away; with an assigned provider, the booking is scheduled from that provider's estimated arrival time. |\n\n## Date, time and time range\n\nThe day and the time of day are both taken from `dateAssignment.date`, kept as the exact instant sent: `2026-10-15T09:00:00.000Z` and `2026-10-15T06:00:00-03:00` schedule the same moment. When `timeRange` is sent, the matching time range is recorded as the booking's period window; the time of day is not moved into the range. When `timeRange` is omitted, any period previously recorded on the booking is cleared.\n\n| Request | Result |\n| --- | --- |\n| `date` only | Booking scheduled at that date and time, no period window. |\n| `date` + `timeRange` | Booking scheduled at that date and time, period window set to the time range. |\n| `timeRange` only | `400 Bad Request`, `date` is required. |\n\n## Which bookings can be rescheduled\n\nBookings with status `on_my_way_to_origin`, `arrived_to_origin`, `on_my_way_to_destination`, `arrived_to_destination`, `left_destination`, `done` or `cancelled` are rejected. Any other status is accepted, including bookings that never had a date.\n\n## Status after the reschedule\n\n| `type` | Booking before | Status after |\n| --- | --- | --- |\n| `direct` | Has an assigned provider | `accepted` |\n| `direct` | No provider, with an assignment mechanism configured | `searching`; Sodtrack starts looking for a provider for the new date. |\n| `direct` | No provider and no assignment mechanism | `waiting_assignment_mechanism` |\n| `userScheduling` | Has an assignment mechanism configured | `waiting_customer_to_set_date` |\n| `userScheduling` | No assignment mechanism | `waiting_assignment_mechanism` |\n| `providerScheduling` | Any | `waiting_provider_to_propose_date` |\n| `onDemand` | Automatic provider assignment | `searching` |\n| `onDemand` | Assigned provider, or no assignment mechanism | `accepted` |\n\nIf the booking was waiting for a provider-proposed date, the pending proposals are cancelled.\n\n## Bundled bookings\n\nRescheduling a booking that belongs to a bundle reschedules the whole bundle: the new date is applied through the bundle head, and every booking in the bundle follows it.\n\n## Side effects\n\nThe reschedule is logged on the booking, the reminder cycle restarts, the provider's agenda is updated when one is assigned, and the usual booking-scheduled and status-change notifications are sent to your configured webhooks.",
        "tags": [
          "Bookings"
        ],
        "parameters": [
          {
            "name": "bookingId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Validation failed (numeric string is expected) — bookingId is not an integer."
          },
          "401": {
            "description": "Missing or invalid x-api-key, or the request does not come from an authorized origin."
          },
          "404": {
            "description": "BOOKING_NOT_FOUND: {bookingId} — No booking exists with that id."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "default": {
            "description": "Reschedule to a date within a time range:",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "scheduledDate": {
                      "type": "string"
                    },
                    "quantity": {
                      "type": "integer"
                    },
                    "totalDurationMinutes": {
                      "type": "integer"
                    },
                    "doneDate": {
                      "type": "null"
                    },
                    "createdDate": {
                      "type": "string"
                    },
                    "customer": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "reference": {
                          "type": "string"
                        }
                      }
                    },
                    "stakeholder": {
                      "type": "null"
                    },
                    "service": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "name": {
                          "type": "string"
                        }
                      }
                    },
                    "variant": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "name": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        },
                        "skus": {
                          "type": "array",
                          "items": {}
                        }
                      }
                    },
                    "category": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "name": {
                          "type": "string"
                        }
                      }
                    },
                    "address": {
                      "type": "object",
                      "properties": {
                        "formattedAddress": {
                          "type": "string"
                        },
                        "coordinates": {
                          "type": "null"
                        }
                      }
                    },
                    "originAddress": {
                      "type": "null"
                    },
                    "saleChannel": {
                      "type": "null"
                    },
                    "project": {
                      "type": "null"
                    },
                    "lead": {
                      "type": "null"
                    },
                    "provider": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "reference": {
                          "type": "null"
                        },
                        "name": {
                          "type": "string"
                        },
                        "lastname": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "phone": {
                          "type": "string"
                        },
                        "identificationNumber": {
                          "type": "null"
                        },
                        "assignedTo": {
                          "type": "null"
                        }
                      }
                    },
                    "bookingBundle": {
                      "type": "null"
                    },
                    "price": {
                      "type": "integer"
                    },
                    "cost": {
                      "type": "integer"
                    },
                    "bookingAddOns": {
                      "type": "array",
                      "items": {}
                    },
                    "products": {
                      "type": "array",
                      "items": {}
                    },
                    "incidents": {
                      "type": "array",
                      "items": {}
                    },
                    "alerts": {
                      "type": "array",
                      "items": {}
                    },
                    "notes": {
                      "type": "array",
                      "items": {}
                    },
                    "dynamicFormSnapshotFields": {
                      "type": "array",
                      "items": {}
                    }
                  }
                },
                "example": {
                  "id": 13,
                  "reference": "BK-2026-0456",
                  "status": "accepted",
                  "scheduledDate": "2026-10-15T09:00:00.000Z",
                  "quantity": 1,
                  "totalDurationMinutes": 60,
                  "doneDate": null,
                  "createdDate": "2026-08-26T04:22:29.911Z",
                  "customer": {
                    "id": 32841,
                    "reference": "CUST-00123"
                  },
                  "stakeholder": null,
                  "service": {
                    "id": 1,
                    "name": "Water heater installation"
                  },
                  "variant": {
                    "id": 1,
                    "name": "Standard installation",
                    "type": "execution",
                    "skus": []
                  },
                  "category": {
                    "id": 1,
                    "name": "Installations"
                  },
                  "address": {
                    "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                    "coordinates": null
                  },
                  "originAddress": null,
                  "saleChannel": null,
                  "project": null,
                  "lead": null,
                  "provider": {
                    "id": 19,
                    "reference": null,
                    "name": "Carlos",
                    "lastname": "Muñoz",
                    "email": "carlos.munoz@example.com",
                    "phone": "+56972345678",
                    "identificationNumber": null,
                    "assignedTo": null
                  },
                  "bookingBundle": null,
                  "price": 0,
                  "cost": 0,
                  "bookingAddOns": [],
                  "products": [],
                  "incidents": [],
                  "alerts": [],
                  "notes": [],
                  "dynamicFormSnapshotFields": []
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/project": {
      "get": {
        "operationId": "projectsGetProjects",
        "summary": "Projects",
        "description": "### **Purpose**\n\nReturns a **paginated** list of **projects**, with the core fields needed to identify a project and know its current state.\n\nFilters can be **combined freely**: every filter you send is applied together, and a project is returned only when it satisfies **all** of them. Projects can be looked up by their own id or reference, and by the customer they belong to.\n\n* * *\n\n#### 🔎 Query parameters\n\n| Parameter | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | `number` | ❌ | Filter by Sodtrack project id. Must be a positive integer. |\n| `reference` | `string` | ❌ | Filter by project external reference. Exact match. |\n| `customerId` | `number` | ❌ | Return the projects belonging to the customer with this Sodtrack id. Must be a positive integer. |\n| `customerReference` | `string` | ❌ | Return the projects belonging to the customer with this external reference. |\n| `pageSize` | `number` | ❌ | Number of results per page. Min `1`, max `50`. Default **`10`**. |\n| `pageNumber` | `number` | ❌ | Page index (**1-based**). Default **`1`**. |\n\n> All filters are optional and can be combined. Sending none returns the paginated list of all projects, ordered by `id` descending.\n\n> Filters sent as empty or whitespace-only strings are ignored, exactly as if they had not been sent. Unrecognized query parameters are ignored.\n\n* * *\n\n### **Example Requests**\n\nRetrieve every project of a customer, using the reference you already hold in your own system:\n\n```\nGET /api/integration/project?customerReference=EXT-CUSTOMER-REF-001\n\n```\n\nRetrieve a single project by its reference:\n\n```\nGET /api/integration/project?reference=EXT-PROJECT-REF-001\n\n```\n\nCombine filters to confirm that a project belongs to a specific customer:\n\n```\nGET /api/integration/project?reference=EXT-PROJECT-REF-001&customerId=2001\n\n```\n\nPaginate the full project list:\n\n```\nGET /api/integration/project?pageSize=25&pageNumber=2\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": 4821,\n      \"reference\": \"EXT-PROJECT-REF-001\",\n      \"name\": \"Instalación red eléctrica - Sucursal Centro\",\n      \"status\": \"in_execution\",\n      \"customer\": {\n        \"id\": 2001,\n        \"reference\": \"EXT-CUSTOMER-REF-001\"\n      },\n      \"startDate\": \"2026-07-14T00:00:00.000Z\",\n      \"endDate\": null,\n      \"createdDate\": \"2026-07-02T13:45:21.000Z\"\n    },\n    {\n      \"id\": 4790,\n      \"reference\": null,\n      \"name\": \"Mantención preventiva - Bodega Norte\",\n      \"status\": \"done\",\n      \"customer\": {\n        \"id\": 2001,\n        \"reference\": \"EXT-CUSTOMER-REF-001\"\n      },\n      \"startDate\": \"2026-05-02T00:00:00.000Z\",\n      \"endDate\": \"2026-06-20T00:00:00.000Z\",\n      \"createdDate\": \"2026-04-28T09:12:03.000Z\"\n    }\n  ],\n  \"metadata\": {\n    \"count\": 7,\n    \"pageNumber\": 1,\n    \"pageSize\": 10,\n    \"totalPages\": 1\n  }\n}\n\n```\n\n#### **Project item (****`data[]`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sodtrack project id. |\n| `reference` | `string` | `null` |\n| `name` | `string` | Project name. |\n| `status` | `string` | Current project status. See **Project status** below. |\n| `customer` | `object` | `null` |\n| `startDate` | `string` (ISO 8601) | `null` |\n| `endDate` | `string` (ISO 8601) | `null` |\n| `createdDate` | `string` (ISO 8601) | Project record creation timestamp. |\n\n#### **Customer (****`data[].customer`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `customer.id` | `number` | Sodtrack customer id. |\n| `customer.reference` | `string` | `null` |\n\n#### **Pagination (****`metadata`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `count` | `number` | Total number of projects matching the filters, across all pages. |\n| `pageNumber` | `number` | Current page (1-based). |\n| `pageSize` | `number` | Page size used for this response. |\n| `totalPages` | `number` | Total pages for the current filters and `pageSize`. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | Validation error | A query parameter has an invalid value: `id` or `customerId` is not a positive integer, `pageSize` is outside `1`–`50`, or `pageNumber` is below `1`. The response body lists the offending parameters. |\n| `401 Unauthorized` | — | `x-api-key` is missing or invalid, or the request does not originate from an authorized network. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\nWhen the filters match no projects, the request still succeeds: `data` is `[]` and `metadata.count` is `0`.\n\n* * *\n\n# Business Rules & Constraints\n\n## Combining filters\n\nEvery filter present in the request is applied together, and only projects satisfying **all** of them are returned.\n\n| Filters sent | Behavior |\n| --- | --- |\n| _(none)_ | All projects, paginated, ordered by `id` descending. |\n| One filter | Projects matching that filter. |\n| Several filters | Only projects matching every filter at once. |\n\nFilters come in two pairs pointing at the same record through different fields: `id` and `reference` identify the project itself, while `customerId` and `customerReference` identify its customer. Sending both members of a pair is a valid way to **confirm** that a record matches on both fields.\n\nPointing two filters at different records is not an error. The request succeeds and returns an empty page, because no single project satisfies both conditions.\n\n## Filtering by customer\n\n`customerId` and `customerReference` return every project belonging to the matching customer, paginated like any other query. A customer with no projects yields an empty page.\n\nOnly the customer assigned to the project is considered.\n\n## Pagination\n\n-   `pageNumber` is **1-based**: the first page is `1`.\n    \n-   Default `pageSize` is **10**, maximum is **50**.\n    \n-   `count` reflects all projects matching the filters, not only those on the current page.\n    \n-   Results are always ordered by `id` descending, so the most recently created projects appear first.\n    \n\n## Project status\n\n`status` reflects the current state of the project:\n\n| Value | Meaning |\n| --- | --- |\n| `created` | Project was created and has not started execution yet. |\n| `in_execution` | Project is currently being executed. |\n| `done` | Project execution finished. |\n| `approved` | Project was approved. |\n| `cancelled` | Project was cancelled. |\n\n## Returned data\n\n-   Timestamps use **ISO 8601** in UTC.",
        "tags": [
          "Projects"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Project Creation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "reference": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "customer": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "reference": {
                                "type": "string"
                              }
                            }
                          },
                          "startDate": {
                            "type": "string"
                          },
                          "endDate": {
                            "type": "null"
                          },
                          "createdDate": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "metadata": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "pageNumber": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 4821,
                      "reference": "PROJ-094883",
                      "name": "Instalación red eléctrica - Sucursal Centro",
                      "status": "in_execution",
                      "customer": {
                        "id": 2001,
                        "reference": "EXT-CUSTOMER-REF-001"
                      },
                      "startDate": "2026-07-14T00:00:00.000Z",
                      "endDate": null,
                      "createdDate": "2026-07-02T13:45:21.000Z"
                    }
                  ],
                  "metadata": {
                    "count": 7,
                    "pageNumber": 1,
                    "pageSize": 10,
                    "totalPages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — A query parameter has an invalid value: id or customerId is not a positive integer, pageSize is outside 1–50, or pageNumber is below 1. The response body lists the offending parameters."
          },
          "401": {
            "description": "x-api-key is missing or invalid, or the request does not originate from an authorized network."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      },
      "post": {
        "operationId": "projectsProjectCreation",
        "summary": "Project Creation",
        "description": "### **Purpose**\n\nCreates a new project in Sodtrack linked to a customer.\n\nThe project is created with the provided **name**, **reference**, and optional **description**. The **customer** is resolved by reference or email: if an existing customer matches, that customer is linked to the project; otherwise a new customer is created and then linked.\n\nProjects created through this endpoint can later be targeted when creating bookings, so that bookings are attached to a stage of that project.\n\n* * *\n\n### **Field Definitions**\n\n#### 📁 Project\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `name` | `string` | ✅ | Project name. |\n| `description` | `string` | ❌ | Optional project description. |\n| `reference` | `string` | ✅ | External system reference for the project. Must be unique across projects. |\n| `customer` | `object` | ✅ | Customer to associate with the project. Used to find an existing customer or to create a new one. |\n\n* * *\n\n#### 🧍 Customer\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customer` | `object` | ✅ | Customer information. |\n| `customer.name` | `string` | ✅ | Customer's first name. |\n| `customer.lastName` | `string` | ❌ | Customer's last name. |\n| `customer.identificationNumber` | `string` | ❌ | National ID or tax identification number. |\n| `customer.identificationNumberCountry` | `string` | ❌ | ISO 3166-1 alpha-2 country code for the identification number. |\n| `customer.phoneNumber` | `string` | ❌ | Contact phone number in international format. |\n| `customer.email` | `string` | ❌ | Customer's email address. When creating a new customer, if missing or invalid a temporary email may be generated. |\n| `customer.reference` | `string` | ❌ | External reference of the customer. Used together with email to resolve an existing customer. |\n\n> If customer is new, one of email, reference or identification numbers should be provided, in order to generate a temporary email for that customer\n\n* * *\n\n### **Example Request (with full customer)**\n\n```json\n{\n  \"name\": \"Instalación cortinas - Av. Providencia\",\n  \"description\": \"Proyecto creado desde sistema externo\",\n  \"reference\": \"PROJ-EXT-100\",\n  \"customer\": {\n    \"name\": \"María\",\n    \"lastName\": \"García\",\n    \"identificationNumber\": \"12345678-9\",\n    \"identificationNumberCountry\": \"CL\",\n    \"phoneNumber\": \"+56912345678\",\n    \"email\": \"maria.garcia@example.com\",\n    \"reference\": \"CUST-EXT-001\"\n  }\n}\n\n```\n\n### **Example Request (minimal)**\n\n```json\n{\n  \"name\": \"Proyecto ejemplo\",\n  \"reference\": \"PROJ-EXT-101\",\n  \"customer\": {\n    \"name\": \"Juan Pérez\",\n    \"email\": \"juanperez@example.com\"\n  }\n}\n\n```\n\n* * *\n\n### **Response Example**\n\n```json\n{\n  \"id\": 502,\n  \"reference\": \"PROJ-EXT-100\"\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack project ID. |\n| `reference` | `string` | The project reference as stored (same as requested). |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `PROJECT_REFERENCE_ALREADY_USED: {reference}` | A project with the given `reference` already exists. The reference must be unique. |\n| `400 Bad Request` | `MULTIPLE_CUSTOMERS_FOUND_FOR_REFERENCE` | More than one customer matches the provided reference/email; resolution is ambiguous. Use a unique reference or contact. |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid. |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Project reference uniqueness\n\n-   The **`reference`** must be unique across all projects in Sodtrack.\n    \n-   If a project with the same `reference` already exists, the request is rejected with `PROJECT_REFERENCE_ALREADY_USED` and no project is created.\n    \n\n* * *\n\n## Customer resolution\n\nThe **customer** object is used to either link an existing customer or create a new one:\n\n-   **Existing customer:** Sodtrack searches by **reference** and **email** (from the request).\n    \n    -   If **exactly one** customer is found, that customer is linked to the new project.\n        \n    -   If **more than one** customer matches, the request fails with `MULTIPLE_CUSTOMERS_FOUND_FOR_REFERENCE`. Ensure your external references or emails uniquely identify a single customer.\n        \n-   **New customer:** If no customer is found, a new customer is created with the provided data. If `email` is missing or invalid, the system may generate a temporary email so the user can be created; the customer can be updated later (e.g. via the administrator or other APIs).\n    \n\n* * *\n\n## Data and format\n\n-   All timestamps follow the ISO 8601 format (UTC) where applicable.",
        "tags": [
          "Projects"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Project Creation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "customer": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "name": "Proyecto ejemplo",
                  "reference": "PROJ-EXT-100",
                  "customer": {
                    "name": "María"
                  }
                }
              }
            }
          },
          "400": {
            "description": "PROJECT_REFERENCE_ALREADY_USED: {reference} — A project with the given reference already exists. The reference must be unique."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/lead": {
      "post": {
        "operationId": "leadsCreateLead",
        "summary": "Create Lead",
        "description": "### **Purpose**\n\nCreates a new lead in Sodtrack for a given **service**.\n\nThe lead is created with **customer** information, required **qualifying questions** (dynamic form field values tied to the service’s lead form), and optional **provider assignment** and **dynamic forms** (additional info). **Address** is optional only for **in-store services**; for non in-store services, a valid location input is required (see **Address and coordinates** in Business Rules).\n\nWhen **address** is sent without coordinates, Sodtrack may attempt to geocode it automatically (when auto-geocoding is enabled for external integration). For services that are not in-store, the lead creation requires a valid location input: **coordinates**, **address text**, or **zip code**; otherwise the request fails with `REQUIRES_ADDRESS_OR_ZIP_CODE` (see **Address and coordinates** in Business Rules).\n\n**Provider assignment** and **dynamic form** snapshots are applied after the lead is created; failures in those steps do not fail the request—the lead is still returned.\n\n* * *\n\n### **Field Definitions**\n\n#### 🧍 **Customer**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customer` | `object` | ✅ | Customer or contact information for the lead. |\n| `customer.name` | `string` | ✅ | Customer's first name. |\n| `customer.lastName` | `string` | ❌ | Customer's last name. |\n| `customer.phoneNumber` | `string` | ❌ | Contact phone number in international format. |\n| `customer.email` | `string` | ❌ | Customer's email address. |\n| `customer.identificationNumber` | `string` | ❌ | National ID or tax identification number. |\n| `customer.identificationNumberCountry` | `string` | ❌ | ISO 3166-1 alpha-2 country code for the identification number. |\n| `customer.reference` | `string` | ❌ | External reference of the customer. |\n\n* * *\n\n#### 🏠 **Address**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `address` | `object` | ❌ | Service or lead location. Required for non in-store services (see Business Rules). |\n| `address.address` | `string` | ❌ | Main address or street. Used for geocoding when coordinates are not provided. |\n| `address.extraInfo` | `string` | ❌ | Additional address details (e.g., apartment, suite number). |\n| `address.coordinate` | `object` | ❌ | Geographic coordinates of the service location. |\n| `address.coordinate.lat` | `number` | ❌ | Latitude. When provided, must be between -90 and 90. |\n| `address.coordinate.lng` | `number` | ❌ | Longitude. When provided, must be between -180 and 180. |\n| `address.associateAddressToCustomer` | `boolean` | ❌ | Whether the address should be stored and associated to the customer. Defaults to **true** when omitted. |\n| `address.zipCode` | `string` | ❌ | Optional zip/postal code. Can be used as location input for non in-store services. |\n\n> If coordinates are not provided but `address.address` is sent, Sodtrack may attempt to geocode the address automatically if its part of your active features.  \n> If the service is not in-store and the request has no coordinates, no address text, and no zip code, the request fails with `REQUIRES_ADDRESS_OR_ZIP_CODE`.\n\n* * *\n\n#### 📋 **Lead context**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `salesChannelId` | `number` | ✅ | Sodtrack sales channel ID. Must exist and be valid. |\n| `serviceId` | `number` | ✅ | Sodtrack service ID. Must exist and have an associated lead form. |\n| `reference` | `string` | ❌ | External reference for the lead. Stored for your tracking; uniqueness is not enforced by this endpoint. |\n\n* * *\n\n#### 🧩 **Qualifying questions**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `qualifyingQuestions` | `array[object]` | ✅ | Answers to the lead form’s qualifying (dynamic) fields. Each entry must reference a dynamic field of the service’s lead form. |\n| `qualifyingQuestions[].fieldReference` | `string` | ✅ | Field reference of the dynamic field in the lead form. Must match a field belonging to the lead form of the given `serviceId`. |\n| `qualifyingQuestions[].value` | `string` | ✅ | Value for the field. |\n\n> Each `fieldReference` must correspond to a dynamic field of the lead form associated with the request’s **service**. Invalid or mismatched references cause the request to fail with `INVALID_QUALIFYING_QUESTION_WITH_ID_REFERENCE`.\n\n* * *\n\n#### 📄 **Dynamic forms (additional info)**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `dynamicForms` | `array[object]` | ❌ | Additional dynamic form snapshots to attach to the lead after creation. Processed after the lead is created; errors are logged and do not fail the request. |\n| `dynamicForms[].formReference` | `string` | ✅ when dynamic form sent | Reference of the form. |\n| `dynamicForms[].values` | `array[object]` | ✅ when dynamic form sent | Field values for the form. |\n| `dynamicForms[].values[].fieldReference` | `string` | ✅ | Reference of the field. |\n| `dynamicForms[].values[].value` | `string` | ✅ | Value for the field. |\n\n* * *\n\n#### 👷 **Provider assignment**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `providerAssignment` | `object` | ❌ | How to assign a provider to the lead. Applied after the lead is created; errors are logged and do not fail the request. |\n| `providerAssignment.type` | `string` | ✅ when providerAssignment sent | Assignment type: `\"direct\"` (specific provider) or `\"automatic\"`. |\n| `providerAssignment.provider` | `object` | ✅ when type = \"direct\" | Provider to assign. Omitted when `type` is `\"automatic\"`. |\n| `providerAssignment.provider.type` | `string` | ✅ when direct | Identifier type: `\"providerId\"` or `\"providerReference\"`. |\n| `providerAssignment.provider.value` | `string` | `number` | ✅ when direct |\n\n* * *\n\n### **Example Request (with address and provider assignment)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"María\",\n    \"lastName\": \"García\",\n    \"phoneNumber\": \"+56912345678\",\n    \"email\": \"maria.garcia@example.com\",\n    \"reference\": \"CUST-EXT-001\"\n  },\n  \"address\": {\n    \"address\": \"Av. Providencia 1234, Santiago\",\n    \"extraInfo\": \"Depto 501\",\n    \"coordinate\": {\n      \"lat\": -33.4372,\n      \"lng\": -70.6506\n    },\n    \"zipCode\": \"7500000\"\n  },\n  \"salesChannelId\": 1,\n  \"serviceId\": 42,\n  \"reference\": \"LEAD-EXT-200\",\n  \"qualifyingQuestions\": [\n    {\n      \"fieldReference\": \"1\",\n      \"value\": \"high\"\n    }\n  ],\n  \"providerAssignment\": {\n    \"type\": \"direct\",\n    \"provider\": {\n      \"type\": \"providerId\",\n      \"value\": 10\n    }\n  }\n}\n\n```\n\n### **Example Request (with zip\\_code)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"María\",\n    \"lastName\": \"García\",\n    \"phoneNumber\": \"+56912345678\",\n    \"email\": \"maria.garcia@example.com\",\n    \"reference\": \"CUST-EXT-001\"\n  },\n  \"address\": {\n    \"zipCode\": \"7500000\"\n  },\n  \"salesChannelId\": 1,\n  \"serviceId\": 42,\n  \"reference\": \"LEAD-EXT-201\",\n  \"qualifyingQuestions\": [\n    {\n      \"fieldReference\": \"1\",\n      \"value\": \"high\"\n    }\n  ]\n}\n\n```\n\n### **Example Request (minimal)**\n\n```json\n{\n  \"customer\": {\n    \"name\": \"Juan Pérez\"\n  },\n  \"salesChannelId\": 1,\n  \"serviceId\": 42,\n  \"qualifyingQuestions\": [\n    {\n      \"fieldReference\": \"1\",\n      \"value\": \"high\"\n    }\n  ]\n}\n\n```\n\n* * *\n\n### **Response Example**\n\n```json\n{\n  \"id\": 1001,\n  \"customer_id\": 502\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack lead ID. |\n| `customer_id` | `number` | Sodtrack customer ID associated with the lead. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `INVALID_SERVICE` | The given `serviceId` does not exist or has no associated lead form. |\n| `400 Bad Request` | `INVALID_SALES_CHANNEL` | The given `salesChannelId` does not exist or is invalid. |\n| `400 Bad Request` | `INVALID_LATITUDE_OR_LONGITUDE` | `address.coordinate` was sent with lat/lng outside valid ranges (lat -90–90, lng -180–180). |\n| `400 Bad Request` | `REQUIRES_ADDRESS_OR_ZIP_CODE` | The service is not an in-store service and the request did not include coordinates, address text, or zip code. |\n| `400 Bad Request` | `INVALID_QUALIFYING_QUESTION_WITH_ID_REFERENCE: {fieldReference}` | A qualifying question `fieldReference` does not match any dynamic field for the service’s lead form. |\n| `400 Bad Request` | `FIELD_REFERENCE_IS_REQUIRED` | A qualifying question entry is missing `fieldReference`. |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid (e.g. validation pipeline). |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Service and sales channel\n\n-   **`serviceId`** must identify an existing Sodtrack service that has an associated lead form. Otherwise the request fails with `INVALID_SERVICE`.\n    \n-   **`salesChannelId`** must identify an existing sales channel. Otherwise the request fails with `INVALID_SALES_CHANNEL`.\n    \n-   For **in-store services**, Sodtrack uses the sales channel address and the request `address` can be omitted.\n    \n-   For **non in-store services**, a valid location input is required: coordinates, address text, or zip code.\n    \n\n* * *\n\n## Address and coordinates\n\n-   **When** **`address`** **is sent with** **`coordinate`\\*\\*\\*\\*:** The system validate those to be valid coordinates. Otherwise the request fails with `INVALID_LATITUDE_OR_LONGITUDE`.\n    \n-   **When** **`address`** **is sent with** **`address`** **(street) but no coordinates:** Sodtrack may attempt to geocode the address automatically when enabled for external integration. If geocoding succeeds, coordinates are filled in; if it fails, they remain missing.\n    \n-   **When the service is not an in-store service:** The lead creation step requires **at least one** valid location input: **coordinates** (`address.coordinate`), **address text** (`address.address`), or **zip code** (`address.zip_code`). If **none** of these are provided, the request fails with `REQUIRES_ADDRESS_OR_ZIP_CODE`.\n    \n\n* * *\n\n## Qualifying questions\n\n-   Each element in **`qualifyingQuestions`** must have a **`fieldReference`** that matches a dynamic field of the **lead form** associated with the request’s **service**.\n    \n-   If a `fieldReference` does not exist or belongs to a different form, the request fails with `INVALID_QUALIFYING_QUESTION_WITH_ID_REFERENCE` (including the invalid reference or a message that the field is not associated with the service’s lead form).\n    \n-   The array can be empty if the lead form has no required qualifying fields.\n    \n\n* * *\n\n## Provider assignment and dynamic forms\n\n-   **Provider assignment** and **dynamic form** snapshots are applied **after** the lead is created.\n    \n-   Failures during provider assignment or dynamic form creation are **logged** but do **not** cause the endpoint to return an error; the response still returns the created lead (`id` and `customer_id`).\n    \n-   For **direct** provider assignment, `provider` with `type` and `value` must be provided; for **automatic**, no `provider` object is needed.\n    \n\n* * *\n\n## Lead reference\n\n-   **`reference`** is an optional external identifier stored with the lead. This endpoint does not enforce uniqueness on `reference`.\n\n* * *\n\n## Data and format\n\n-   All timestamps follow the ISO 8601 format (UTC) where applicable.\n    \n-   Customer and address data are stored as provided; identification country should be ISO 3166-1 alpha-2 where applicable.",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Create Lead",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "customer_id": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "id": 4,
                  "customer_id": 15
                }
              }
            }
          },
          "400": {
            "description": "INVALID_SERVICE — The given serviceId does not exist or has no associated lead form."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/lead/cancel": {
      "patch": {
        "operationId": "leadsCancelLead",
        "summary": "Cancel Lead",
        "description": "## General Description\n\nThis endpoint cancels an existing lead throug## General Description\n\nThis endpoint cancels an existing lead through the Integration API. The lead is identified in the request body by either lead ID or lead reference.\n\nIn addition to the cancellation comment, the endpoint optionally accepts dynamic form answers in the same external integration format used in booking/lead flows (`formReference` + `values[]` with `fieldReference` and `value`).\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationCancelLeadRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `lead` | ExternalIntegrationLeadIdentifierRequestDTO | Yes | Lead identifier object. Supports lookup by lead ID or lead reference. |\n| `comment` | string | No | Cancellation reason/comment persisted as lead cancel reason. |\n| `dynamicForms` | CreateDynamicFormSnapshotFromExternalIntegrationRequestDTO\\[\\] | No | Optional list of dynamic form answers to store as lead dynamic form snapshots on cancellation flow. |\n\n### ExternalIntegrationLeadIdentifierRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Type of lead identifier. Must be one of: `leadId` or `leadReference`. |\n| `value` | string | Yes | The lead ID (if type is `leadId`) or lead reference (if type is `leadReference`). |\n\n### CreateDynamicFormSnapshotFromExternalIntegrationRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `formReference` | string | Yes | Dynamic form reference configured in Sodtrack. |\n| `values` | CreateBookingDynamicFormFieldValueV2RequestDTO\\[\\] | Yes | List of dynamic field answers for the form. |\n\n### CreateBookingDynamicFormFieldValueV2RequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `fieldReference` | string | Yes | Dynamic form field reference to answer. |\n| `value` | string | Yes | Value to persist for the selected field. |\n\n### Success Response\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| \\- | \\- | \\- | `200 OK`. Lead cancellation operation completed. |\n\n* * *\n\n## Business Rules & Constraints\n\n-   The lead must exist (`leadId` or `leadReference` lookup). If not found, the endpoint returns `LEAD_NOT_FOUND`.\n    \n-   `comment` is required and is used as the lead cancellation reason.\n    \n-   `dynamicForms` is optional. When present, each item is transformed into a dynamic form snapshot\n    \n-   Dynamic form snapshot validation is executed before persistence. Invalid form references or invalid values for the fields, return validation/business errors (`400 Bad Request`).\n    \n\n* * *\n\n## Example Request\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadReference\",\n    \"value\": \"LEAD-EXT-342\"\n  },\n  \"comment\": \"Customer canceled due to schedule conflict.\",\n  \"dynamicForms\": [\n    {\n      \"formReference\": \"lead-cancel-reasons-v1\",\n      \"values\": [\n        {\n          \"fieldReference\": \"cancel_reason\",\n          \"value\": \"customer_unavailable\"\n        },\n        {\n          \"fieldReference\": \"cancel_details\",\n          \"value\": \"Customer requested cancellation by phone.\"\n        }\n      ]\n    }\n  ]\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\n\n```\n\n## Example Error Response\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"LEAD_NOT_FOUND\",\n  \"error\": \"Bad Request\"\n}\n\n```",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": "{\n    \"lead\": {\n        \"type\": \"string\", // one off: \"leadId\" or \"leadReference\",\n        \"value\": \"string\" // value of the leadId or leadReference\n    },\n    \"comment\": \"string\"\n}"
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancel Lead"
          }
        }
      }
    },
    "/api/integration/lead/assign-provider": {
      "patch": {
        "operationId": "leadsAssignProvider",
        "summary": "Assign provider",
        "description": "## General Description\n\nThis endpoint assigns a lead to a specific provider (`direct`) or switches the lead to automatic provider assignment (`automatic`). The lead is identified in the request body by either lead ID or lead reference.\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationAssignProviderLeadRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `lead` | ExternalIntegrationLeadIdentifierRequestDTO | Yes | Lead identifier object. Supports lookup by lead ID or lead reference. |\n| `providerAssignment` | ProviderAssignmentFromExternalIntegrationRequestDTO | Yes | Provider assignment strategy. Use `direct` to assign a specific provider or `automatic` to trigger automatic provider flow. |\n\n### ExternalIntegrationLeadIdentifierRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Type of lead identifier. Must be one of: `leadId` or `leadReference`. |\n| `value` | string | Yes | The lead ID (if type is `leadId`) or lead reference (if type is `leadReference`). |\n\n### ProviderAssignmentFromExternalIntegrationRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Assignment strategy. Must be one of: `direct` or `automatic`. |\n| `provider` | providerInputToSearchInExternalIntegrationRequestDTO | No | Provider selector. Required when `type` is `direct`; ignored when `type` is `automatic`. |\n\n### providerInputToSearchInExternalIntegrationRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Type of provider identifier. Must be one of: `providerId` or `providerReference`. |\n| `value` | string | number | Yes |\n\n* * *\n\n## Business Rules & Constraints\n\n-   The lead must exist (`leadId` or `leadReference` lookup). If not found, the endpoint returns `LEAD_NOT_FOUND`.\n    \n-   For `direct` assignment:\n    \n    -   Provider must be resolvable from `provider.type` + `provider.value`.\n        \n    -   `provider.type` must be one of: `providerId`, `providerReference`.\n        \n    -   Lead status must not be `CANCELLED` or `DONE`.\n        \n-   For `automatic` assignment:\n    \n    -   Lead status must not be `CANCELLED` or `DONE`.\n        \n    -   Lead must not already have a booking or project.\n        \n-   If lead assignment constraints fail, the endpoint returns `400 Bad Request` with the corresponding validation/business error.\n    \n\n* * *\n\n## Example Request (Direct Assignment)\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadReference\",\n    \"value\": \"LEAD-EXT-001\"\n  },\n  \"providerAssignment\": {\n    \"type\": \"direct\",\n    \"provider\": {\n      \"type\": \"providerReference\",\n      \"value\": \"PROV-001\"\n    }\n  }\n}\n\n```\n\n## Example Request (Automatic Assignment)\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadId\",\n    \"value\": \"342\"\n  },\n  \"providerAssignment\": {\n    \"type\": \"automatic\"\n  }\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\n\n```\n\n## Example Error Response\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"Lead cannot be updated to automatic provider assignment, it has a booking already\",\n  \"error\": \"Bad Request\"\n}\n\n```",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "value": {
                        "type": "string"
                      }
                    }
                  },
                  "providerAssignment": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "provider": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string"
                          },
                          "value": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "lead": {
                  "type": "leadReference",
                  "value": "LEAD-EXT-342"
                },
                "providerAssignment": {
                  "type": "direct",
                  "provider": {
                    "type": "providerReference",
                    "value": "PROV-001"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Assign provider"
          }
        }
      }
    },
    "/api/integration/lead/note": {
      "post": {
        "operationId": "leadsCreateNote",
        "summary": "Create Note",
        "description": "### **Purpose**\n\nCreates a new note associated with an existing lead in Sodtrack.\n\nThe lead is identified in the request body by either **lead ID** or **lead reference**.  \nThe note is created in the context of the **issuer** user when possible, and an optional **reference** can be used to correlate the note with an external system.\n\n* * *\n\n### **Field Definitions**\n\n#### 🧾 Request Body\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `lead` | `object` | ✅ | Lead identifier object. Supports lookup by lead ID or lead reference. |\n| `note` | `string` | ✅ | Note text to create on the lead. |\n| `issuer` | `object` | ✅ | Issuer payload. `email` is used to resolve an existing user if possible. |\n| `isShareable` | `boolean` | ❌ | Visibility flag for the note. Defaults to **true** when omitted. |\n| `reference` | `string` | ❌ | Optional external reference for the note (e.g. from an external system). |\n\n* * *\n\n#### 🎯 Lead Identifier\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `lead.type` | `string` | ✅ | Type of lead identifier. Must be one of: `\"leadId\"` or `\"leadReference\"`. |\n| `lead.value` | `string` | ✅ | The lead ID (if `type = \"leadId\"`) or lead reference (if `type = \"leadReference\"`). |\n\n* * *\n\n#### 👤 Issuer\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `issuer.name` | `string` | ✅ | Issuer first name. |\n| `issuer.lastName` | `string` | ✅ | Issuer last name. |\n| `issuer.email` | `string` | ✅ | Issuer email used to search an existing Sodtrack user. |\n\n* * *\n\n### **Example Request (issuer user found)**\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadReference\",\n    \"value\": \"LEAD-EXT-342\"\n  },\n  \"note\": \"Customer requested a callback in the afternoon.\",\n  \"issuer\": {\n    \"name\": \"Maria\",\n    \"lastName\": \"Fernandez\",\n    \"email\": \"maria.fernandez@example.com\"\n  },\n  \"isShareable\": true,\n  \"reference\": \"NOTE-EXT-001\"\n}\n```\n\n### **Example Request (minimal)**\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadId\",\n    \"value\": \"5678\"\n  },\n  \"note\": \"Follow-up call completed.\",\n  \"issuer\": {\n    \"name\": \"Support\",\n    \"lastName\": \"Team\",\n    \"email\": \"support@example.com\"\n  }\n}\n```\n\n* * *\n\n### **Response Example**\n\n```http\nHTTP/1.1 200 OK\n```\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `LEAD_NOT_FOUND` | The lead could not be found for the given `leadId` or `leadReference`. |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid. |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Lead resolution\n\n-   The lead is resolved from the **`lead`** object:\n    -   **`type = \"leadId\"`**: `value` must be a valid lead ID.\n    -   **`type = \"leadReference\"`**: `value` must be a valid lead reference.\n-   If the lead is not found, the endpoint returns **`LEAD_NOT_FOUND`** and no note is created.\n\n* * *\n\n## Issuer resolution\n\nThe issuer is resolved using **`issuer.email`**:\n\n-   **If a user with that email exists in Sodtrack:**\n    -   The note is linked to that user (`note.user_id = user.id`).\n    -   The note text is augmented with contextual information (e.g. `Created via API`).\n-   **If no user is found for `issuer.email`:**\n    -   The note is created **without** a linked user (`note.user_id = null`).\n    -   The issuer full name (`name` + `lastName`) is embedded in the note text (e.g. `Note by {name} {lastName}: ...`).\n\n`name` and `lastName` should still be provided even when the issuer might not exist in Sodtrack, so the platform can record who authored the note from the external system.\n\n* * *\n\n## Visibility (isShareable)\n\n-   **`isShareable`** controls whether the note is shareable/visible according to your Sodtrack configuration.\n-   When **`isShareable`** is omitted, it defaults to **true**.\n\n* * *\n\n## Reference\n\n-   **`reference`** is optional and stored as-is to help correlate notes with external or upstream systems (e.g. ticket IDs, case IDs).\n-   Sodtrack does **not** enforce uniqueness or any specific format for `reference`.\n-   You can use this field for idempotency or traceability on your side.\n\n* * *\n\n## Data and format\n\n-   All timestamps in responses (when present) follow the ISO 8601 format (UTC).",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Create Note"
          },
          "400": {
            "description": "LEAD_NOT_FOUND — The lead could not be found for the given leadId or leadReference."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/lead/reinstate": {
      "patch": {
        "operationId": "leadsReinstateLead",
        "summary": "Reinstate Lead",
        "description": "## General Description\n\nThis endpoint reinstates a previously cancelled lead. The lead is identified in the request body by either lead ID or lead reference.\n\nReinstating a lead rolls it back to its latest non-cancelled status found in lead status history. The lead cancel reason is cleared.\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationReinstateLeadRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `lead` | ExternalIntegrationLeadIdentifierRequestDTO | Yes | Lead identifier object (ID or reference lookup). |\n\n### ExternalIntegrationLeadIdentifierRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Type of lead identifier. Must be one of: `leadId` or `leadReference`. |\n| `value` | string | Yes | The lead ID (if type is `leadId`) or lead reference (if type is `leadReference`). |\n\n### Success Response\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| \\- | \\- | \\- | `200 OK`. Lead reinstate operation completed. |\n\n* * *\n\n## Business Rules & Constraints\n\n-   The lead must exist (`leadId` or `leadReference` lookup). If not found, the endpoint returns `LEAD_NOT_FOUND`.\n    \n-   The lead must currently be in status `CANCELLED`. Otherwise, the endpoint returns `LEAD_NOT_IN_CANCELLED_STATUS`.\n    \n-   The lead must have at least one non-cancelled status in `lead_status_history`. Otherwise, the endpoint returns `LEAD_HAS_NO_PREVIOUS_STATUS`.\n    \n-   On success, the lead status is set to the latest non-cancelled history status and `cancelReason` is cleared.\n    \n\n* * *\n\n## Example Request (Lead reference)\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadReference\",\n    \"value\": \"LEAD-EXT-252\"\n  }\n}\n\n```\n\n## Example Request (Lead id)\n\n```json\n{\n  \"lead\": {\n    \"type\": \"leadId\",\n    \"value\": \"252\"\n  }\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\n\n```\n\n## Example Error Response: Lead Not Found\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"LEAD_NOT_FOUND\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n## Example Error Response: Lead Not In Cancelled Status\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"LEAD_NOT_IN_CANCELLED_STATUS\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n## Example Error Response: No Previous Status\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"LEAD_HAS_NO_PREVIOUS_STATUS\",\n  \"error\": \"Bad Request\"\n}\n\n```",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "value": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "lead": {
                  "type": "leadId",
                  "value": "252"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reinstate Lead"
          }
        }
      }
    },
    "/api/integration/work-order": {
      "post": {
        "operationId": "workOrdersCreateWorkOrder",
        "summary": "Create work order",
        "description": "### **Purpose**\n\nCreates one or more work orders in Sodtrack from an external system.\n\nA single request targets one product and a `quantity`; **one work order is created per unit of** **`quantity`**, and the response is an array with one entry per created work order.\n\nThe customer is resolved or created automatically. The service variant and product are resolved from the references you provide. Optionally, you can assign an existing provider, attribute the work orders to a sales channel, and associate specific product units to the first work orders.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | External integration API key provided by Sodtrack. |\n\n* * *\n\n### **Field Definitions**\n\n#### 🧾 **Work order**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `reference` | `string` | ✅ | External reference stored on every created work order. |\n| `quantity` | `integer` | ✅ | Number of work orders to create (minimum `1`). |\n\n#### 🧍 **Customer**\n\nThe customer is matched by email first, then by reference; if no match exists it is created.\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customer.name` | `string` | ✅ | Customer first name / name. |\n| `customer.lastName` | `string` | ❌ | Customer last name. |\n| `customer.email` | `string` | ❌ | Used as the primary identity to match an existing customer. |\n| `customer.reference` | `string` | ❌ | External reference; used to match a customer when email does not match. |\n| `customer.identificationType` | `string` | ❌ | One of: `\"PASSPORT\"`, `\"DRIVER_LICENSE\"`, `\"NATIONAL_ID\"`, `\"TAX_ID\"`, `\"OTHER\"`. |\n| `customer.identificationNumber` | `string` | ❌ | Identification number. |\n| `customer.identificationNumberCountry` | `string` | ❌ | Country of the identification number. |\n| `customer.phoneType` | `string` | ❌ | One of: `\"MOBILE\"`, `\"HOME\"`, `\"WORK\"`. |\n| `customer.phoneNumber` | `string` | ❌ | Phone number. |\n\n#### 🧩 **Service variant**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `workOrderServiceVariant.type` | `string` | ✅ | One of: `\"variantId\"`, `\"externalReference\"`. Determines how `value` is interpreted. |\n| `workOrderServiceVariant.value` | `string` | ✅ | Internal variant id when `type` is `\"variantId\"`, or the variant external reference when `type` is `\"externalReference\"`. |\n\n#### 📦 **Product**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `product.type` | `string` | ✅ | One of: `\"productId\"`, `\"productSku\"`, `\"productSerialNumber\"`. |\n| `product.value` | `string` | ✅ | Product id / sku / unit serial number, per `type`. When a serial number is sent, the product that owns that unit is used. |\n\n#### 📦 **Product units** _(optional)_\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `productUnits` | `array` | ❌ | Units to associate. Length must be `<= quantity`; the first work orders are associated at product-unit level, the rest only at product level. |\n| `productUnits[].type` | `string` | ✅ when a unit is sent | One of: `\"productUnitId\"`, `\"productSerialNumber\"`. |\n| `productUnits[].value` | `string` | ✅ when a unit is sent | Product unit id or unit serial number, per `type`. |\n\n#### 👷 **Provider assignment** _(optional)_\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `providerReference` | `string` | ❌ | Reference of an **existing** provider to assign to all created work orders. If omitted, the work orders are created without a provider. |\n\n#### 📣 **Sales channel** _(optional)_\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `saleChannel.type` | `string` | ✅ when object sent | One of: `\"reference\"`, `\"id\"`. Determines how `value` is interpreted. |\n| `saleChannel.value` | `string` | ✅ when object sent | Sales channel reference when `type` is `\"reference\"`, or the numeric sales channel id (sent as a string) when `type` is `\"id\"`. |\n\n> The sales channel is applied to every created work order. It is not echoed back in the response.\n\n#### 🧍 **Stakeholder** _(optional)_\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `stakeholder.name` | `string` | ✅ when stakeholder sent | Stakeholder name. |\n| `stakeholder.lastname` | `string` | ❌ | Stakeholder last name. |\n| `stakeholder.reference` | `string` | ❌ | External reference. |\n| `stakeholder.email` | `string` | ❌ | Email. |\n| `stakeholder.phone` | `string` | ❌ | Phone. |\n| `stakeholder.identificationNumber` | `string` | ❌ | Identification number. |\n| `stakeholder.identificationNumberCountry` | `string` | ❌ | Country of the identification number. |\n\n* * *\n\n### **Example Request**\n\n```json\n{\n  \"reference\": \"EXT-WO-0001\",\n  \"quantity\": 1,\n  \"customer\": {\n    \"name\": \"María\",\n    \"lastName\": \"Gómez\",\n    \"email\": \"maria.gomez@example.com\",\n    \"reference\": \"EXT-CUSTOMER-002\"\n  },\n  \"providerReference\": \"PROVIDER-REF-A\",\n  \"workOrderServiceVariant\": { \"type\": \"externalReference\", \"value\": \"SERVICE-VARIANT-REF\" },\n  \"saleChannel\": { \"type\": \"reference\", \"value\": \"SALES-CHANNEL-WEB\" },\n  \"product\": { \"type\": \"productSku\", \"value\": \"MOTO-HND-CG125\" },\n  \"productUnits\": [{ \"type\": \"productSerialNumber\", \"value\": \"CG125-CHS-2401\" }]\n}\n\n```\n\n**Minimal valid request**\n\n```json\n{\n  \"reference\": \"EXT-WO-0002\",\n  \"quantity\": 1,\n  \"customer\": { \"name\": \"Juan\" },\n  \"workOrderServiceVariant\": { \"type\": \"variantId\", \"value\": \"18\" },\n  \"product\": { \"type\": \"productId\", \"value\": \"6\" }\n}\n\n```\n\n### **Response Example**\n\n```json\n[\n  {\n    \"id\": 1024,\n    \"externalReference\": \"EXT-WO-0001\",\n    \"customer\": { \"id\": 2001, \"name\": \"María\", \"lastname\": \"Gómez\", \"email\": \"maria.gomez@example.com\" },\n    \"provider\": { \"id\": 3001, \"name\": \"Taller Motos Racing\" },\n    \"stakeholder\": null,\n    \"workOrderServiceVariant\": { \"id\": 18, \"name\": \"Service 10.000 km\" },\n    \"product\": { \"id\": 1, \"sku\": \"MOTO-HND-CG125\", \"name\": \"Honda CG 125\" },\n    \"productUnit\": { \"id\": 1, \"serialNumber\": \"CG125-CHS-2401\" },\n    \"executionDateTime\": null\n  }\n]\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier of the created work order. |\n| `externalReference` | `string` | The `reference` sent in the request. |\n| `customer` | `object` | Customer summary (id, name, last name, email). |\n| `provider` | `object` | Assigned provider summary, or `null` if no provider was assigned. |\n| `stakeholder` | `object` | Stakeholder summary, or `null` if none was sent. |\n| `workOrderServiceVariant` | `object` | Resolved service variant summary. |\n| `product` | `object` | Resolved product data (id, sku, name, …). |\n| `productUnit` | `object` | Associated product unit, or `null` if the work order is only at product level. |\n| `executionDateTime` | `string` | Scheduled execution date-time, or `null`. This endpoint assigns a provider but does not schedule, so it is `null`. |\n\n> One response entry is returned per created work order (`quantity` entries).\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | A required field is missing or invalid (e.g. `quantity` < 1, or `type` not in the allowed values for variant / product / product units). |\n| `400 Bad Request` | — | A referenced entity could not be resolved: service variant, product (by sku), product unit (by serial), or `providerReference` not found. Also when `productUnits` length exceeds `quantity`. |\n| `400 Bad Request` | `INVALID_SALES_CHANNEL` | `saleChannel.value` is not a valid sales channel reference, or is not a positive integer when `type` is `\"id\"`. |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`. |\n| `404 Not Found` | — | `saleChannel.type` is `\"id\"` and no sales channel exists with that id. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Quantity and response\n\n`quantity` work orders are created for the product, and the response is an array with one entry per work order.\n\n## Customer resolution\n\nThe customer is matched by `email` first, then by `reference`. If a match is found it is reused as-is; if not, a new customer is created. Sending the same `email` repeatedly resolves to the same customer.\n\n## Provider assignment\n\n`providerReference` must match an **existing** provider — this endpoint does not create providers. When provided, the provider is assigned to every created work order. When omitted, the work orders are created without a provider (it can be assigned later). Scheduling is not performed here, so `executionDateTime` is `null`.\n\n## Sales channel attribution\n\n`saleChannel` is optional. When sent, the resolved sales channel is applied to every work order created by the request; when omitted, the work orders are created without one.\n\n| Selector | `value` contains | Not found |\n| --- | --- | --- |\n| `saleChannel.type = \"reference\"` | Sales channel reference. | `400 Bad Request` with `INVALID_SALES_CHANNEL`. |\n| `saleChannel.type = \"id\"` | Numeric sales channel id, sent as a string. | `404 Not Found`. A non-numeric or non-positive value returns `400 Bad Request` with `INVALID_SALES_CHANNEL`. |\n\nThe sales channel is not returned in the response.\n\n## Service variant and product resolution\n\n| Selector | `value` contains |\n| --- | --- |\n| `workOrderServiceVariant.type = \"variantId\"` | Internal variant id. |\n| `workOrderServiceVariant.type = \"externalReference\"` | Variant external reference. |\n| `product.type = \"productId\"` | Internal product id. |\n| `product.type = \"productSku\"` | Product sku. |\n| `product.type = \"productSerialNumber\"` | A unit serial number; the product that owns that unit is used. |\n\n## Product unit association\n\n`productUnits` length must be `<= quantity`. The first work orders are associated at product-unit level (in the order provided); any remaining work orders are associated only at product level. Each unit is identified by `productUnitId` or `productSerialNumber`.",
        "tags": [
          "Work orders"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Create work order",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "integer"
                      },
                      "externalReference": {
                        "type": "string"
                      },
                      "customer": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "lastname": {
                            "type": "string"
                          },
                          "email": {
                            "type": "string"
                          }
                        }
                      },
                      "provider": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "stakeholder": {
                        "type": "null"
                      },
                      "workOrderServiceVariant": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "product": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "sku": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "productUnit": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "serialNumber": {
                            "type": "string"
                          }
                        }
                      },
                      "executionDateTime": {
                        "type": "null"
                      }
                    }
                  }
                },
                "example": [
                  {
                    "id": 1024,
                    "externalReference": "EXT-WO-0001",
                    "customer": {
                      "id": 2001,
                      "name": "María",
                      "lastname": "Gómez",
                      "email": "maria.gomez@example.com"
                    },
                    "provider": {
                      "id": 3001,
                      "name": "Taller Motos Racing"
                    },
                    "stakeholder": null,
                    "workOrderServiceVariant": {
                      "id": 18,
                      "name": "Service 10.000 km"
                    },
                    "product": {
                      "id": 1,
                      "sku": "MOTO-HND-CG125",
                      "name": "Honda CG 125"
                    },
                    "productUnit": {
                      "id": 1,
                      "serialNumber": "CG125-CHS-2401"
                    },
                    "executionDateTime": null
                  }
                ]
              }
            }
          },
          "400": {
            "description": "InvalidParameters — A required field is missing or invalid (e.g. quantity < 1, or type not in the allowed values for variant / product / product units)."
          },
          "401": {
            "description": "Missing or invalid x-api-key."
          },
          "404": {
            "description": "saleChannel.type is \"id\" and no sales channel exists with that id."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/budget/execution/{budgetExecutionId}/approve": {
      "patch": {
        "operationId": "budgetsApproveBudgetExecution",
        "summary": "Approve budget execution",
        "description": "### **Purpose**\n\nApproves a budget execution that is awaiting an approval decision.\n\nApproving is what moves a budget execution forward in the operation. When the budget execution is configured to create its execution bookings automatically on approval, Sodtrack creates those bookings as part of the same request and returns their ids in the response, so the client does not need a second call to discover them.\n\nThe budget execution is identified by its Sodtrack id in the URL. This endpoint does not take a request body.\n\n```\nPATCH /api/integration/budget/execution/{budgetExecutionId}/approve\n\n```\n\n* * *\n\n### **Field Definitions**\n\n#### 🔐 Authentication\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `x-api-key` | `header` | ✅ | Sodtrack integration API key. Requests without a valid key are rejected. |\n\n#### 📦 Path parameters\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `budgetExecutionId` | `string` | ✅ | Sodtrack id of the budget execution to approve. |\n\n> This endpoint does not accept a request body. Any payload sent is ignored.\n\n* * *\n\n### **Example Request**\n\n```\nPATCH /api/integration/budget/execution/1234/approve\nx-api-key: <your-api-key>\n\n```\n\n### **Response Example**\n\nBudget execution configured to create its execution bookings automatically:\n\n```json\n{\n  \"id\": \"1234\",\n  \"status\": \"approved\",\n  \"executionBookingIds\": [8871, 8872]\n}\n\n```\n\nBudget execution that does not create bookings automatically:\n\n```json\n{\n  \"id\": \"1234\",\n  \"status\": \"approved\",\n  \"executionBookingIds\": []\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `string` | Sodtrack id of the approved budget execution. |\n| `status` | `string` | Always `\"approved\"` on a successful response. |\n| `executionBookingIds` | `array[number]` | Ids of the execution bookings created by this approval. Empty when the budget execution does not create bookings automatically. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `INVALID_STATUS_TO_RESOLVE_APPROVAL` | The budget execution is not in a status that accepts an approval decision, typically because it was already approved. |\n| `401 Unauthorized` | — | The API key is missing, invalid, or the request origin is not authorized. |\n| `404 Not Found` | `BUDGET_EXECUTION_NOT_FOUND` | No budget execution exists for the given id. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Statuses that accept an approval\n\nA budget execution can be approved only while it is still open to a decision. The following statuses are accepted:\n\n| Status | Meaning |\n| --- | --- |\n| `created` | Draft, not yet submitted for approval. |\n| `in_progress` | Legacy equivalent of `created`. |\n| `provider_submitted` | Submitted by the provider. |\n| `waiting_internal_review` | Awaiting internal review. |\n| `waiting_admin_approval` | Awaiting administrator approval. |\n| `waiting_customer_approval` | Awaiting customer approval. |\n| `rejected` | Previously rejected; can be approved afterwards. |\n| `customer_rejected` | Legacy equivalent of `rejected`. |\n\nAny other status, in particular a budget execution that is already `approved`, is rejected with `400 INVALID_STATUS_TO_RESOLVE_APPROVAL`.\n\n## Execution booking creation\n\nWhether approving creates bookings depends on the approval policy configured for the service variant of the budget execution, not on anything the client sends.\n\n| Configuration | Behavior |\n| --- | --- |\n| Bookings created on approval | Sodtrack creates the execution bookings during the request and returns their ids in `executionBookingIds`. |\n| Bookings created manually | No booking is created. `executionBookingIds` is empty. The bookings are created later through the Sodtrack back office. |\n| No approval configuration | No booking is created. `executionBookingIds` is empty. |\n\nWhen the budget execution has milestones, one execution booking is created per milestone, so `executionBookingIds` can contain several ids. They are returned in the order the bookings were created.",
        "tags": [
          "Budgets"
        ],
        "parameters": [
          {
            "name": "budgetExecutionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "dev.api.cl.sodtrack.sodtrack.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Approve budget execution",
            "content": {
              "text/plain": {
                "example": {
                  "id": "901",
                  "status": "approved",
                  "executionBookingIds": [
                    5372
                  ]
                }
              }
            }
          },
          "400": {
            "description": "INVALID_STATUS_TO_RESOLVE_APPROVAL — The budget execution is not in a status that accepts an approval decision, typically because it was already approved."
          },
          "401": {
            "description": "The API key is missing, invalid, or the request origin is not authorized."
          },
          "404": {
            "description": "BUDGET_EXECUTION_NOT_FOUND — No budget execution exists for the given id."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/product": {
      "post": {
        "operationId": "productCreateProduct",
        "summary": "Create product",
        "description": "### **Purpose**\n\nCreates a product or component in the Sodtrack catalog from an external system.\n\nThe endpoint accepts the core product data plus optional classification (category, brand) and tags. Category, brand, and tags are resolved **by name**: if they do not already exist in Sodtrack, they are created automatically. The product `type` lets you create either a standard product or a component.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | External integration API key provided by Sodtrack. |\n\n* * *\n\n### **Field Definitions**\n\n#### 📦 **Product**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `sku` | `string` | ✅ | Unique product/component code. Must not already exist in Sodtrack. |\n| `name` | `string` | ✅ | Display name of the product/component. |\n| `description` | `string` | ❌ | Free-text description. |\n| `category` | `string` | ❌ | Category name. Created automatically if it does not exist. |\n| `brand` | `string` | ❌ | Brand name. Created automatically if it does not exist. |\n| `type` | `string` | ❌ | One of: `\"product\"`, `\"component\"`. Defaults to `\"product\"` when omitted. |\n\n#### 🏷️ **Tags**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `tags` | `array` | ❌ | Tags to associate with the product. |\n| `tags[].name` | `string` | ✅ when a tag is sent | Tag name. Created automatically if it does not exist. |\n| `tags[].value` | `string` | ✅ when a tag is sent | Value assigned to the tag for this product. |\n\n* * *\n\n### **Example Request**\n\n```json\n{\n  \"sku\": \"COMP-0001\",\n  \"name\": \"Oil filter\",\n  \"description\": \"High-flow oil filter\",\n  \"category\": \"Filters\",\n  \"brand\": \"K&N\",\n  \"type\": \"component\",\n  \"tags\": [\n    { \"name\": \"Origin\", \"value\": \"Imported\" },\n    { \"name\": \"Warranty\", \"value\": \"12 months\" }\n  ]\n}\n\n```\n\n**Minimal valid request**\n\n```json\n{\n  \"sku\": \"PROD-1001\",\n  \"name\": \"Maintenance kit\"\n}\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"id\": \"326\",\n  \"sku\": \"COMP-0001\",\n  \"name\": \"Oil filter\",\n  \"description\": \"High-flow oil filter\",\n  \"category\": \"Filters\",\n  \"brand\": \"K&N\",\n  \"type\": \"component\"\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `string` | Unique Sodtrack identifier of the created product. |\n| `sku` | `string` | Product/component code. |\n| `name` | `string` | Display name. |\n| `description` | `string` | Description, or `null` if not provided. |\n| `category` | `string` | Resolved category name, or `null`. |\n| `brand` | `string` | Resolved brand name, or `null`. |\n| `type` | `string` | `\"product\"` or `\"component\"`. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | A required field (`sku`, `name`) is missing or a field has an invalid value (e.g. unsupported `type`). |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`. |\n| `406 Not Acceptable` | `PRODUCT.SKU_ALREADY_IN_USE` | A product with the given `sku` already exists. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Type resolution\n\nWhen `type` is omitted, the product is created as `\"product\"`. Send `\"component\"` to create a component.\n\n## Category, brand and tag resolution\n\n`category`, `brand`, and each `tags[].name` are matched by name. If the name does not exist in Sodtrack, it is created automatically and then associated with the product. Existing entities are reused.\n\n## SKU uniqueness\n\n`sku` must be unique. Creating a product with an existing `sku` is rejected with `406 PRODUCT.SKU_ALREADY_IN_USE`.",
        "tags": [
          "Product"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Create product",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "sku": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "brand": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": "326",
                  "sku": "COMP-0001",
                  "name": "Oil filter",
                  "description": "High-flow oil filter",
                  "category": "Filters",
                  "brand": "K&N",
                  "type": "component"
                }
              }
            }
          },
          "400": {
            "description": "InvalidParameters — A required field (sku, name) is missing or a field has an invalid value (e.g. unsupported type)."
          },
          "401": {
            "description": "Missing or invalid x-api-key."
          },
          "406": {
            "description": "PRODUCT.SKU_ALREADY_IN_USE — A product with the given sku already exists."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      },
      "patch": {
        "operationId": "productUpdateProduct",
        "summary": "Update product",
        "description": "### **Purpose**\n\nUpdates an existing product or component in the Sodtrack catalog, identified by its internal id or its sku.\n\nThis is a **partial update**: only the fields you send are changed. The target product is selected through the `product` object, which specifies whether you are addressing it by internal id or by sku. The updated product is returned in full.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | External integration API key provided by Sodtrack. |\n\n* * *\n\n### **Field Definitions**\n\n#### 🔎 **Product selector**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `product` | `object` | ✅ | Identifies the product/component to update. |\n| `product.type` | `string` | ✅ | One of: `\"productId\"`, `\"productSku\"`. Determines how `product.value` is interpreted. |\n| `product.value` | `string` | ✅ | Internal Sodtrack id when `type` is `\"productId\"`, or the sku when `type` is `\"productSku\"`. |\n\n#### 📦 **Product (fields to update)**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `name` | `string` | ❌ | New display name. Left unchanged if omitted. |\n| `description` | `string` | ❌ | New description. Left unchanged if omitted. |\n| `category` | `string` | ❌ | Category name. Created automatically if it does not exist. |\n| `brand` | `string` | ❌ | Brand name. Created automatically if it does not exist. |\n\n#### 🏷️ **Tags**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `tags` | `array` | ❌ | When sent, **replaces** the product's full tag set. Omit to leave tags untouched. |\n| `tags[].name` | `string` | ✅ when a tag is sent | Tag name. Created automatically if it does not exist. |\n| `tags[].value` | `string` | ✅ when a tag is sent | Value assigned to the tag. |\n\n* * *\n\n### **Example Request — by sku**\n\n```json\n{\n  \"product\": { \"type\": \"productSku\", \"value\": \"COMP-0001\" },\n  \"description\": \"High-flow oil filter (updated)\",\n  \"category\": \"Filters\",\n  \"brand\": \"K&N\",\n  \"tags\": [\n    { \"name\": \"Warranty\", \"value\": \"24 months\" }\n  ]\n}\n\n```\n\n### **Example Request — by internal id**\n\n```json\n{\n  \"product\": { \"type\": \"productId\", \"value\": \"326\" },\n  \"name\": \"Oil filter premium\"\n}\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"id\": \"316\",\n  \"sku\": \"COMP-0001\",\n  \"name\": \"Oil filter premium\",\n  \"description\": \"High-flow oil filter (updated)\",\n  \"category\": \"Filters\",\n  \"brand\": \"K&N\",\n  \"type\": \"component\"\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `string` | Unique Sodtrack identifier of the product. |\n| `sku` | `string` | Product/component code. |\n| `name` | `string` | Display name. |\n| `description` | `string` | Description, or `null`. |\n| `category` | `string` | Resolved category name, or `null`. |\n| `brand` | `string` | Resolved brand name, or `null`. |\n| `type` | `string` | `\"product\"` or `\"component\"`. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | The `product` selector is missing/invalid, or `product.type` is not `\"productId\"` / `\"productSku\"`. |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`. |\n| `404 Not Found` | — | No product exists for the given id or sku. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Product selection\n\n| `product.type` | `product.value` contains |\n| --- | --- |\n| `\"productId\"` | The internal Sodtrack id of the product. |\n| `\"productSku\"` | The sku of the product. |\n\nOnly `\"productId\"` and `\"productSku\"` are supported. Any other selector type is rejected with `400 Bad Request`.\n\n## Partial update\n\nOnly the fields present in the request are modified. Omitted fields keep their current values.\n\n## Tag replacement\n\nWhen `tags` is included, the product's existing tags are **replaced** by the provided set. To keep current tags, omit the `tags` field. Sending an empty `name`/`value` is not valid.",
        "tags": [
          "Product"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Update product",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "sku": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "brand": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": "316",
                  "sku": "COMP-0001",
                  "name": "Oil filter premium",
                  "description": "High-flow oil filter (updated)",
                  "category": "Filters",
                  "brand": "K&N",
                  "type": "component"
                }
              }
            }
          },
          "400": {
            "description": "InvalidParameters — The product selector is missing/invalid, or product.type is not \"productId\" / \"productSku\"."
          },
          "401": {
            "description": "Missing or invalid x-api-key."
          },
          "404": {
            "description": "No product exists for the given id or sku."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      },
      "get": {
        "operationId": "productGetProduct",
        "summary": "Product",
        "description": "### **Purpose**\n\nReturns a single product or component, identified by its Sodtrack id or by its SKU, together with its catalog price and every **area pricing** configuration it has: each configuration carries the price, the cost, the areas it applies to and the currency of those areas.\n\nUse it to know how a product is priced in each geographic area before creating bookings, work orders or quotes that reference it.\n\n* * *\n\n### **Field Definitions**\n\n#### 🔎 **Query parameters**\n\n| Parameter | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | `number` | ✅ when `sku` not sent | Product id in Sodtrack. Positive integer (minimum `1`). |\n| `sku` | `string` | ✅ when `id` not sent | Product SKU. |\n\n> Send **exactly one** of `id` or `sku`. Sending none, or both, is rejected with `400 Bad Request`.\n\n* * *\n\n### **Example Request**\n\n```\nGET /api/integration/product?id=5\nGET /api/integration/product?sku=MOTO-SUZ-GN125\n```\n\n### **Response Example**\n\n```json\n{\n  \"id\": \"5\",\n  \"sku\": \"MOTO-SUZ-GN125\",\n  \"name\": \"Suzuki GN 125\",\n  \"description\": \"Motocicleta urbana 125cc\",\n  \"category\": \"Motocicletas Urbanas\",\n  \"brand\": \"Suzuki\",\n  \"type\": \"product\",\n  \"price\": 2100,\n  \"areaPricingItems\": [\n    {\n      \"id\": 38,\n      \"price\": 2600,\n      \"cost\": 1600,\n      \"currency\": {\n        \"id\": 8,\n        \"name\": \"USD\",\n        \"symbol\": \"$\"\n      },\n      \"areas\": [\n        {\n          \"id\": 15,\n          \"name\": \"Ciudad de Guatemala\",\n          \"reference\": \"AREA-GT-CITY\"\n        }\n      ]\n    },\n    {\n      \"id\": 39,\n      \"price\": 2400,\n      \"cost\": 1500,\n      \"currency\": {\n        \"id\": 8,\n        \"name\": \"USD\",\n        \"symbol\": \"$\"\n      },\n      \"areas\": [\n        {\n          \"id\": 9,\n          \"name\": \"San Salvador\",\n          \"reference\": \"AREA-SV-SS\"\n        },\n        {\n          \"id\": 10,\n          \"name\": \"Santa Ana\",\n          \"reference\": \"AREA-SV-SA\"\n        }\n      ]\n    },\n    {\n      \"id\": 40,\n      \"price\": 39999,\n      \"cost\": 25000,\n      \"currency\": {\n        \"id\": 3,\n        \"name\": \"MXN\",\n        \"symbol\": \"$\"\n      },\n      \"areas\": [\n        {\n          \"id\": 21,\n          \"name\": \"Ciudad de México\",\n          \"reference\": \"AREA-MX-CDMX\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nProduct without any area pricing configured:\n\n```json\n{\n  \"id\": \"2\",\n  \"sku\": \"MOTO-HND-WAVE110\",\n  \"name\": \"Honda Wave 110\",\n  \"description\": \"Motocicleta urbana 110cc\",\n  \"category\": \"Motocicletas Urbanas\",\n  \"brand\": \"Honda\",\n  \"type\": \"product\",\n  \"price\": 1800,\n  \"areaPricingItems\": []\n}\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `string` | Product id in Sodtrack. |\n| `sku` | `string` | Product SKU. |\n| `name` | `string` | Product name. |\n| `description` | `string` | Product description. |\n| `category` | `string` | Category name. Omitted when the product has no category. |\n| `brand` | `string` | Brand name. Omitted when the product has no brand. |\n| `type` | `string` | `\"product\"` or `\"component\"`. |\n| `price` | `number` | `null` | Catalog price of the product. `null` when no catalog price is loaded. Its currency is not informed. |\n| `areaPricingItems` | `array` | Area pricing configurations of the product (see **Area pricing item**). Empty when none is configured. |\n\n#### **Area pricing item (`areaPricingItems[]`)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Configuration id. |\n| `price` | `number` | `null` | Unit price in the areas of this configuration. |\n| `cost` | `number` | `null` | Unit cost in the areas of this configuration. |\n| `currency` | `object` | `null` | Currency shared by the areas of this configuration (`id`, `name`, `symbol`). `null` when the areas have no currency assigned. |\n| `areas` | `array` | Areas the configuration applies to (see **Area**). |\n\n#### **Area (`areaPricingItems[].areas[]`)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Area id. |\n| `name` | `string` | Area name. |\n| `reference` | `string` | `null` | Area external reference. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | ``Exactly one of `id` or `sku` must be provided`` | Neither or both identifiers were sent. |\n| `400 Bad Request` | `id must be an integer number` / `id must not be less than 1` | `id` is not a positive integer. |\n| `404 Not Found` | `Product with id {id} not found` / `Product with sku '{sku}' not found` | No product matches the identifier. |\n| `403 Forbidden` | — | The request origin is not allowed. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Product identification\n\n-   `id` and `sku` identify the same product through different fields; exactly one must be sent.\n-   Both products (`type = \"product\"`) and components (`type = \"component\"`) are supported and return the same structure.\n-   SKU matching is exact.\n\n## Catalog price\n\n`price` is the product price stored in the Sodtrack catalog, independent of any area. A catalog price of `0` means no price was loaded and is returned as `null`. The catalog price has no currency associated.\n\n## Area pricing items\n\n-   Each entry in `areaPricingItems` is one price/cost configuration valid for **all** the areas listed in its `areas`. An area belongs to at most one configuration of the same product.\n-   All the areas of a configuration share the same currency, which is exposed once as `currency`.\n-   `areaPricingItems` lists every configuration stored for the product, including those whose area pricing is currently inactive and those without a price. When resolving the price of a booking or work order, Sodtrack only applies active configurations with a price; inactive or priceless configurations fall back to the catalog price.\n\n## Data and format\n\n-   Query parameter values are passed as strings in the URL; `id` is coerced to an integer before validation.\n-   Unknown query parameters are ignored.",
        "tags": [
          "Product"
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Exactly one of id or sku must be provided — Neither or both identifiers were sent."
          },
          "403": {
            "description": "The request origin is not allowed."
          },
          "404": {
            "description": "Product with id {id} not found / Product with sku '{sku}' not found — No product matches the identifier."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "default": {
            "description": "GET Product",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "sku": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "brand": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "price": {
                      "type": "integer"
                    },
                    "areaPricingItems": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "price": {
                            "type": "integer"
                          },
                          "cost": {
                            "type": "integer"
                          },
                          "currency": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "symbol": {
                                "type": "string"
                              }
                            }
                          },
                          "areas": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "reference": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "id": "5",
                  "sku": "MOTO-SUZ-GN125",
                  "name": "Suzuki GN 125",
                  "description": "Motocicleta urbana 125cc",
                  "category": "Motocicletas Urbanas",
                  "brand": "Suzuki",
                  "type": "product",
                  "price": 2100,
                  "areaPricingItems": [
                    {
                      "id": 38,
                      "price": 2600,
                      "cost": 1600,
                      "currency": {
                        "id": 8,
                        "name": "USD",
                        "symbol": "$"
                      },
                      "areas": [
                        {
                          "id": 15,
                          "name": "Ciudad de Guatemala",
                          "reference": "AREA-GT-CITY"
                        }
                      ]
                    },
                    {
                      "id": 39,
                      "price": 2400,
                      "cost": 1500,
                      "currency": {
                        "id": 8,
                        "name": "USD",
                        "symbol": "$"
                      },
                      "areas": [
                        {
                          "id": 9,
                          "name": "San Salvador",
                          "reference": "AREA-SV-SS"
                        },
                        {
                          "id": 10,
                          "name": "Santa Ana",
                          "reference": "AREA-SV-SA"
                        }
                      ]
                    },
                    {
                      "id": 40,
                      "price": 39999,
                      "cost": 25000,
                      "currency": {
                        "id": 3,
                        "name": "MXN",
                        "symbol": "$"
                      },
                      "areas": [
                        {
                          "id": 21,
                          "name": "Ciudad de México",
                          "reference": "AREA-MX-CDMX"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/product-unit": {
      "get": {
        "operationId": "productUnitsGetFullProductUnit",
        "summary": "Get Full Product Unit",
        "description": "### **Purpose**\n\nReturns **everything Sodtrack knows about one product unit**, located either by its Sodtrack id or by its serial number.\n\nSend exactly one of the two identifiers. Use `id` when you hold the Sodtrack id (for example from the customer product units endpoint); use `serialNumber` when you only know the physical unit.\n\nThe response combines, in a single call:\n\n-   The unit itself: serial number, status, type, parent product, the warehouse it entered through and the movement that brought it to its current location.\n-   The **acquisitions** it belongs to and the customer of each one.\n-   The **warranties** in force for the unit, base and extended.\n-   Its full **movement history**, including origin and destination names and addresses.\n-   The **bookings** (service history) in which the unit took part.\n-   The **work orders** associated to the unit.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | Sodtrack inbound integration API key. |\n\nThe endpoint is restricted to Sodtrack's private integration network. Requests from unauthorized origins are rejected.\n\n* * *\n\n### **Endpoint**\n\n`GET /api/integration/product-unit`\n\n* * *\n\n### **Field Definitions**\n\n#### 📦 **Unit identifier** (query parameters)\n\nExactly one of the two must be sent.\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | `number` | ✅ when `serialNumber` is absent | Sodtrack product unit id. Integer, minimum `1`. |\n| `serialNumber` | `string` | ✅ when `id` is absent | Serial number of the unit. Leading and trailing spaces are ignored; otherwise matched exactly, case-sensitive. URL-encode it if it contains reserved characters. |\n\nNo other parameter is accepted; any other query parameter is ignored.\n\n* * *\n\n### **Example Request**\n\nBy Sodtrack id:\n\n```\nGET /api/integration/product-unit?id=83\n```\n\nBy serial number:\n\n```\nGET /api/integration/product-unit?serialNumber=SN-0001-A\n```\n\n### **Response Example**\n\n```json\n{\n  \"id\": 83,\n  \"serialNumber\": \"SN-0001-A\",\n  \"status\": \"in_use\",\n  \"type\": \"product\",\n  \"entryDate\": \"2026-08-09T00:19:48.979Z\",\n  \"cost\": null,\n  \"product\": {\n    \"id\": 990001,\n    \"name\": \"Water heater 80L\",\n    \"sku\": \"WH-80L\"\n  },\n  \"lastMovement\": {\n    \"id\": 75,\n    \"createdDate\": \"2026-08-29T00:19:48.984Z\",\n    \"fromLocationType\": \"warehouse\",\n    \"fromId\": \"1\",\n    \"fromName\": \"Central warehouse\",\n    \"fromAddress\": null,\n    \"toLocationType\": \"customer\",\n    \"toId\": \"32841\",\n    \"toName\": \"María González\",\n    \"toAddress\": {\n      \"id\": 13,\n      \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n      \"extraInfo\": \"Floor 3, Apt B\"\n    }\n  },\n  \"firstWarehouse\": {\n    \"id\": 1,\n    \"name\": \"Central warehouse\"\n  },\n  \"acquisitions\": [\n    {\n      \"id\": \"73521\",\n      \"reference\": \"ACQ-2026-0001\",\n      \"acquisitionDate\": \"2026-08-09T03:00:00.000Z\",\n      \"customer\": {\n        \"id\": 32841,\n        \"reference\": \"CUST-00123\",\n        \"name\": \"María\",\n        \"lastname\": \"González\",\n        \"createdDate\": \"2026-08-31T20:23:12.693Z\"\n      }\n    }\n  ],\n  \"warranties\": [\n    {\n      \"id\": \"60511\",\n      \"validityStartDate\": \"2026-08-09T03:00:00.000Z\",\n      \"warranty\": {\n        \"id\": \"990001\",\n        \"name\": \"Base warranty 12 months\",\n        \"externalReference\": \"W-BASE-12\",\n        \"type\": \"BASE\",\n        \"durationValue\": 12,\n        \"durationMetric\": {\n          \"id\": 990003,\n          \"name\": \"Months\"\n        }\n      }\n    },\n    {\n      \"id\": \"60512\",\n      \"validityStartDate\": \"2027-08-09T03:00:00.000Z\",\n      \"warranty\": {\n        \"id\": \"990002\",\n        \"name\": \"Extended warranty 24 months\",\n        \"externalReference\": \"W-EXT-24\",\n        \"type\": \"EXTENDED\",\n        \"durationValue\": 24,\n        \"durationMetric\": {\n          \"id\": 990003,\n          \"name\": \"Months\"\n        }\n      }\n    }\n  ],\n  \"movements\": [\n    {\n      \"id\": 75,\n      \"createdDate\": \"2026-08-29T00:19:48.984Z\",\n      \"fromLocationType\": \"warehouse\",\n      \"fromId\": \"1\",\n      \"fromName\": \"Central warehouse\",\n      \"fromAddress\": null,\n      \"toLocationType\": \"customer\",\n      \"toId\": \"32841\",\n      \"toName\": \"María González\",\n      \"toAddress\": {\n        \"id\": 13,\n        \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n        \"extraInfo\": \"Floor 3, Apt B\"\n      }\n    },\n    {\n      \"id\": 43,\n      \"createdDate\": \"2026-08-09T03:19:48.000Z\",\n      \"fromLocationType\": \"warehouse\",\n      \"fromId\": \"2\",\n      \"fromName\": \"Regional warehouse\",\n      \"fromAddress\": null,\n      \"toLocationType\": \"warehouse\",\n      \"toId\": \"1\",\n      \"toName\": \"Central warehouse\",\n      \"toAddress\": null\n    }\n  ],\n  \"bookings\": [\n    {\n      \"id\": 13,\n      \"reference\": \"BK-2026-0456\",\n      \"status\": \"accepted\",\n      \"scheduledDate\": \"2026-08-26T04:22:29.911Z\",\n      \"quantity\": 1,\n      \"totalDurationMinutes\": 60,\n      \"doneDate\": null,\n      \"createdDate\": \"2026-08-26T04:22:29.911Z\",\n      \"customer\": {\n        \"id\": 32841,\n        \"reference\": \"CUST-00123\"\n      },\n      \"stakeholder\": null,\n      \"service\": {\n        \"id\": 1,\n        \"name\": \"Water heater installation\"\n      },\n      \"variant\": {\n        \"id\": 1,\n        \"name\": \"Standard installation\",\n        \"type\": \"execution\",\n        \"skus\": []\n      },\n      \"category\": {\n        \"id\": 1,\n        \"name\": \"Installations\"\n      },\n      \"address\": {\n        \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n        \"coordinates\": null\n      },\n      \"originAddress\": null,\n      \"saleChannel\": null,\n      \"project\": null,\n      \"lead\": null,\n      \"provider\": {\n        \"id\": 19,\n        \"reference\": null,\n        \"name\": \"Carlos\",\n        \"lastname\": \"Muñoz\",\n        \"email\": \"carlos.munoz@example.com\",\n        \"phone\": \"+56972345678\",\n        \"identificationNumber\": null,\n        \"assignedTo\": null\n      },\n      \"bookingBundle\": null,\n      \"price\": 0,\n      \"cost\": 0,\n      \"bookingAddOns\": [],\n      \"products\": [\n        {\n          \"id\": 5,\n          \"name\": \"Water heater 80L\",\n          \"sku\": \"WH-80L\",\n          \"productType\": \"product\",\n          \"quantity\": 1,\n          \"serialNumber\": \"SN-0001-A\",\n          \"pricing\": {\n            \"price\": 39999,\n            \"cost\": 25000,\n            \"currency\": {\n              \"id\": 3,\n              \"name\": \"MXN\",\n              \"symbol\": \"$\"\n            }\n          }\n        }\n      ],\n      \"incidents\": [],\n      \"alerts\": [],\n      \"notes\": [],\n      \"dynamicFormSnapshotFields\": []\n    }\n  ],\n  \"workOrders\": [\n    {\n      \"id\": 990005,\n      \"createdDate\": \"2026-07-08T13:40:30.755Z\",\n      \"service\": {\n        \"id\": 2,\n        \"name\": \"General inspection\"\n      },\n      \"provider\": {\n        \"id\": 9,\n        \"reference\": \"PROV-001\",\n        \"name\": \"Ava\",\n        \"lastname\": \"Provider\",\n        \"email\": \"ava.provider@example.com\",\n        \"phone\": null,\n        \"identificationNumber\": null,\n        \"assignedTo\": null\n      }\n    }\n  ]\n}\n```\n\n#### **Response Fields**\n\n##### 📦 Product unit\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sodtrack product unit id. |\n| `serialNumber` | `string | null` | Serial number of the unit. |\n| `status` | `string` | One of: `\"available\"`, `\"not_available\"`, `\"committed\"`, `\"in_use\"`, `\"potential_conflict\"`, `\"movement_request\"`. |\n| `type` | `string` | `\"product\"` or `\"component\"`. |\n| `entryDate` | `string (datetime) | null` | When the unit entered Sodtrack's inventory. |\n| `cost` | `number | null` | Unit cost, when registered. |\n| `product` | `object` | Parent product. |\n| `product.id` | `number` | Sodtrack product id. |\n| `product.name` | `string` | Product name. |\n| `product.sku` | `string` | Product SKU. |\n| `lastMovement` | `object | null` | Movement that brought the unit to its current location. Same shape as `movements[]`. `null` when the unit has no movement history. |\n| `firstWarehouse` | `object | null` | Warehouse the unit entered through, that is, the destination of its earliest warehouse-bound movement. `null` when the unit never went through a warehouse. |\n| `firstWarehouse.id` | `number` | Sodtrack warehouse id. |\n| `firstWarehouse.name` | `string` | Warehouse name. |\n\n##### 🧾 Acquisitions (`acquisitions[]`)\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `acquisitions[].id` | `string` | Sodtrack acquisition id. |\n| `acquisitions[].reference` | `string | null` | Your reference for the acquisition. |\n| `acquisitions[].acquisitionDate` | `string (datetime)` | Acquisition date. |\n| `acquisitions[].customer` | `object | null` | Customer of the acquisition. `null` when the customer no longer exists in Sodtrack. |\n| `acquisitions[].customer.id` | `number` | Sodtrack customer id. |\n| `acquisitions[].customer.reference` | `string | null` | Your external reference for the customer. |\n| `acquisitions[].customer.name` | `string | null` | Customer first name. |\n| `acquisitions[].customer.lastname` | `string | null` | Customer last name. |\n| `acquisitions[].customer.createdDate` | `string (datetime)` | When the customer was created in Sodtrack. |\n\n##### 🛡️ Warranties (`warranties[]`)\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `warranties[].id` | `string` | Id of the warranty in force for this unit. |\n| `warranties[].validityStartDate` | `string (datetime) | null` | When the coverage starts. |\n| `warranties[].warranty` | `object` | The warranty definition. |\n| `warranties[].warranty.id` | `string` | Sodtrack warranty id. |\n| `warranties[].warranty.name` | `string` | Warranty name. |\n| `warranties[].warranty.externalReference` | `string | null` | Your reference for the warranty. |\n| `warranties[].warranty.type` | `string` | `\"BASE\"` or `\"EXTENDED\"`. |\n| `warranties[].warranty.durationValue` | `number | null` | Coverage duration, expressed in `durationMetric`. |\n| `warranties[].warranty.durationMetric` | `object | null` | Unit of the duration. |\n| `warranties[].warranty.durationMetric.id` | `number` | Sodtrack metric id. |\n| `warranties[].warranty.durationMetric.name` | `string` | Metric name, for example months or usage hours. |\n\n##### 🚚 Movements (`movements[]`)\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `movements[].id` | `number` | Movement id. |\n| `movements[].createdDate` | `string (datetime) | null` | When the movement happened. |\n| `movements[].fromLocationType` | `string | null` | Origin type: `\"warehouse\"`, `\"customer\"` or `\"provider\"`. `null` for the unit's initial entry. |\n| `movements[].fromId` | `string | null` | Id of the origin warehouse or customer, according to `fromLocationType`. |\n| `movements[].fromName` | `string | null` | Name of the origin warehouse or customer. |\n| `movements[].fromAddress` | `object | null` | Origin address, when the origin is a customer address. Same shape as `toAddress`. |\n| `movements[].toLocationType` | `string` | Destination type: `\"warehouse\"`, `\"customer\"` or `\"provider\"`. |\n| `movements[].toId` | `string` | Id of the destination warehouse or customer, according to `toLocationType`. |\n| `movements[].toName` | `string | null` | Name of the destination warehouse or customer. |\n| `movements[].toAddress` | `object | null` | Destination address, when the destination is a customer address. |\n| `movements[].toAddress.id` | `number` | Sodtrack address id. |\n| `movements[].toAddress.formattedAddress` | `string` | Full formatted address. |\n| `movements[].toAddress.extraInfo` | `string | null` | Additional address details (floor, apartment, notes). |\n\n##### 🧩 Bookings (`bookings[]`)\n\nEach entry is a full Sodtrack booking, in the same shape returned by the booking endpoints of the integration API.\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `bookings[].id` | `number` | Sodtrack booking id. |\n| `bookings[].reference` | `string | null` | Your reference for the booking. |\n| `bookings[].status` | `string` | Booking status. One of: `\"created\"`, `\"searching\"`, `\"accepted\"`, `\"on_my_way_to_origin\"`, `\"arrived_to_origin\"`, `\"on_my_way_to_destination\"`, `\"arrived_to_destination\"`, `\"left_destination\"`, `\"done\"`, `\"cancelled\"`, `\"waiting_customer_to_set_date\"`, `\"waiting_scheduling_mechanism\"`, `\"waiting_assignment_mechanism\"`, `\"waiting_provider_to_propose_date\"`, `\"waiting_customer_to_accept_proposed_date\"`. |\n| `bookings[].scheduledDate` | `string (datetime) | null` | Scheduled execution date. |\n| `bookings[].quantity` | `number` | Quantity booked. |\n| `bookings[].totalDurationMinutes` | `number | null` | Total duration in minutes. |\n| `bookings[].doneDate` | `string (datetime) | null` | When the booking was completed. |\n| `bookings[].createdDate` | `string (datetime)` | When the booking was created. |\n| `bookings[].customer` | `object | null` | `id` and `reference` of the customer. |\n| `bookings[].stakeholder` | `object | null` | `id` and `reference` of the requesting party, when different from the customer. |\n| `bookings[].service` | `object | null` | `id` and `name` of the service. |\n| `bookings[].variant` | `object | null` | Service variant: `id`, `name`, `type` (`\"budget\"` or `\"execution\"`) and `skus` (array of product SKUs linked to the variant). |\n| `bookings[].category` | `object | null` | `id` and `name` of the service category. |\n| `bookings[].address` | `object | null` | Execution address: `formattedAddress` and `coordinates` (`lat`, `lng`, or `null`). |\n| `bookings[].originAddress` | `object | null` | Origin address for transport services. Same shape as `address`. |\n| `bookings[].saleChannel` | `object | null` | Sale channel: `id`, `name`, `reference` and `coordinates`. |\n| `bookings[].project` | `object | null` | `id` and `reference` of the project the booking belongs to. |\n| `bookings[].lead` | `object | null` | `id` and `reference` of the originating lead. |\n| `bookings[].provider` | `object | null` | Assigned provider: `id`, `reference`, `name`, `lastname`, `email`, `phone`, `identificationNumber` and `assignedTo` (`name`, `lastname`, `email` of the executing technician when the provider is a network, otherwise `null`). |\n| `bookings[].bookingBundle` | `object | null` | When the booking is part of a bundle: `bundleHead` and `bundledBookings[]`, each with `id` and `reference`. |\n| `bookings[].price` | `number | null` | Booking price. |\n| `bookings[].cost` | `number | null` | Booking cost. |\n| `bookings[].bookingAddOns[]` | `array` | Add-ons: `id`, `name`, `reference`. |\n| `bookings[].products[]` | `array` | Products in the booking: `id`, `name`, `sku`, `productType` (`\"product\"` or `\"component\"`), `quantity`, `serialNumber` and `pricing` (`price`, `cost`, `currency` with `id`, `name`, `symbol`). |\n| `bookings[].incidents[]` | `array` | Incidents: `id` and `reference`. |\n| `bookings[].alerts[]` | `array` | Alerts: `id` and `reference`. |\n| `bookings[].notes[]` | `array` | Notes: `id`, `note`, `reference`. |\n| `bookings[].dynamicFormSnapshotFields[]` | `array` | Dynamic form answers captured during the booking: `id`, `reference`, `value`, `secondaryValue`, `type`, `snapshotId`. |\n\n##### 🛠️ Work orders (`workOrders[]`)\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `workOrders[].id` | `number` | Sodtrack work order id. |\n| `workOrders[].createdDate` | `string (datetime)` | When the work order was created. |\n| `workOrders[].service` | `object | null` | `id` and `name` of the service. `null` when the work order has no service yet. |\n| `workOrders[].provider` | `object | null` | Assigned provider, same shape as `bookings[].provider`. `null` when unassigned. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `Provide exactly one of \\`id\\` or \\`serialNumber\\`\\` | Neither identifier was sent, or both were. |\n| `400 Bad Request` | — | `id` is not a positive integer, or `serialNumber` is empty. |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`, or the request does not come from an authorized origin. |\n| `404 Not Found` | `PRODUCT_UNIT_NOT_FOUND: {identifier}` | No product unit exists with that id or serial number. The message echoes the identifier sent. |\n| `503 Service Unavailable` | `PRODUCT_MODULE_UNAVAILABLE` | Sodtrack's product inventory service could not be reached. Retry later. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## One identifier at a time\n\n`id` and `serialNumber` are two ways of pointing at the same unit, not filters to combine. Sending both, or none, is rejected with `400 Bad Request` before any lookup.\n\n| Request | Behavior |\n| --- | --- |\n| `?id=83` | Returns the unit with id 83. |\n| `?serialNumber=SN-0001-A` | Returns the unit whose serial number is exactly `SN-0001-A`. |\n| `?id=83&serialNumber=SN-0001-A` | `400 Bad Request`. |\n| no parameters | `400 Bad Request`. |\n\n## Serial number matching\n\nLeading and trailing spaces are removed from `serialNumber` before matching; internal spaces and letter case must match the value registered in Sodtrack. Serial numbers are expected to be unique; if the same value were registered on more than one unit, the first registered one is returned.\n\n## Lists are complete\n\n`acquisitions`, `warranties`, `movements`, `bookings` and `workOrders` are returned in full. There is no pagination on this endpoint. An empty array means the unit has no records of that kind.\n\n## Ordering of each list\n\n| List | Order |\n| --- | --- |\n| `movements` | Newest first. The first entry is always `lastMovement`. |\n| `bookings` | Newest first, by Sodtrack booking id. |\n| `workOrders` | By execution date, earliest first; work orders without an execution date come last. Ties by creation date. |\n| `acquisitions` | No guaranteed order. |\n| `warranties` | No guaranteed order. |\n\n## Only active acquisitions are returned\n\nAcquisitions that were voided are not included in `acquisitions`, even if the unit was part of them.\n\n## Location names and addresses are resolved when possible\n\n`fromName`, `toName`, `fromAddress` and `toAddress` in each movement are resolved from the warehouse or customer referenced by the movement. If that warehouse or customer no longer exists, the name or address comes back as `null` while the raw `fromId` / `toId` is still returned.\n\n## First warehouse\n\n`firstWarehouse` is the destination of the earliest movement of the unit whose destination is a warehouse. A unit registered directly at a customer, with no warehouse in its history, returns `null`.\n\n## Bookings and work orders are matched by the unit\n\n`bookings` contains the bookings in which this specific unit was part of the products serviced. `workOrders` contains the work orders explicitly associated to this unit. Bookings or work orders created for the parent product without naming a unit are not included.",
        "tags": [
          "Product Units"
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Provide exactly one of \\id\\ or \\serialNumber\\\\ — Neither identifier was sent, or both were."
          },
          "401": {
            "description": "Missing or invalid x-api-key, or the request does not come from an authorized origin."
          },
          "404": {
            "description": "PRODUCT_UNIT_NOT_FOUND: {identifier} — No product unit exists with that id or serial number. The message echoes the identifier sent."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "503": {
            "description": "PRODUCT_MODULE_UNAVAILABLE — Sodtrack's product inventory service could not be reached. Retry later."
          },
          "default": {
            "description": "Get Product Unit By Serial Number",
            "content": {
              "text/plain": {
                "example": {
                  "id": 83,
                  "serialNumber": "SN-0001-A",
                  "status": "in_use",
                  "type": "product",
                  "entryDate": "2026-08-09T00:19:48.979Z",
                  "cost": null,
                  "product": {
                    "id": 990001,
                    "name": "Water heater 80L",
                    "sku": "WH-80L"
                  },
                  "lastMovement": {
                    "id": 75,
                    "createdDate": "2026-08-29T00:19:48.984Z",
                    "fromLocationType": "warehouse",
                    "fromId": "1",
                    "fromName": "Central warehouse",
                    "fromAddress": null,
                    "toLocationType": "customer",
                    "toId": "32841",
                    "toName": "María González",
                    "toAddress": {
                      "id": 13,
                      "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                      "extraInfo": "Floor 3, Apt B"
                    }
                  },
                  "firstWarehouse": {
                    "id": 1,
                    "name": "Central warehouse"
                  },
                  "acquisitions": [
                    {
                      "id": "73521",
                      "reference": "ACQ-2026-0001",
                      "acquisitionDate": "2026-08-09T03:00:00.000Z",
                      "customer": {
                        "id": 32841,
                        "reference": "CUST-00123",
                        "name": "María",
                        "lastname": "González",
                        "createdDate": "2026-08-31T20:23:12.693Z"
                      }
                    }
                  ],
                  "warranties": [
                    {
                      "id": "60511",
                      "validityStartDate": "2026-08-09T03:00:00.000Z",
                      "warranty": {
                        "id": "990001",
                        "name": "Base warranty 12 months",
                        "externalReference": "W-BASE-12",
                        "type": "BASE",
                        "durationValue": 12,
                        "durationMetric": {
                          "id": 990003,
                          "name": "Months"
                        }
                      }
                    },
                    {
                      "id": "60512",
                      "validityStartDate": "2027-08-09T03:00:00.000Z",
                      "warranty": {
                        "id": "990002",
                        "name": "Extended warranty 24 months",
                        "externalReference": "W-EXT-24",
                        "type": "EXTENDED",
                        "durationValue": 24,
                        "durationMetric": {
                          "id": 990003,
                          "name": "Months"
                        }
                      }
                    }
                  ],
                  "movements": [
                    {
                      "id": 75,
                      "createdDate": "2026-08-29T00:19:48.984Z",
                      "fromLocationType": "warehouse",
                      "fromId": "1",
                      "fromName": "Central warehouse",
                      "fromAddress": null,
                      "toLocationType": "customer",
                      "toId": "32841",
                      "toName": "María González",
                      "toAddress": {
                        "id": 13,
                        "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                        "extraInfo": "Floor 3, Apt B"
                      }
                    },
                    {
                      "id": 43,
                      "createdDate": "2026-08-09T03:19:48.000Z",
                      "fromLocationType": "warehouse",
                      "fromId": "2",
                      "fromName": "Regional warehouse",
                      "fromAddress": null,
                      "toLocationType": "warehouse",
                      "toId": "1",
                      "toName": "Central warehouse",
                      "toAddress": null
                    }
                  ],
                  "bookings": [
                    {
                      "id": 13,
                      "reference": "BK-2026-0456",
                      "status": "accepted",
                      "scheduledDate": "2026-08-26T04:22:29.911Z",
                      "quantity": 1,
                      "totalDurationMinutes": 60,
                      "doneDate": null,
                      "createdDate": "2026-08-26T04:22:29.911Z",
                      "customer": {
                        "id": 32841,
                        "reference": "CUST-00123"
                      },
                      "stakeholder": null,
                      "service": {
                        "id": 1,
                        "name": "Water heater installation"
                      },
                      "variant": {
                        "id": 1,
                        "name": "Standard installation",
                        "type": "execution",
                        "skus": []
                      },
                      "category": {
                        "id": 1,
                        "name": "Installations"
                      },
                      "address": {
                        "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                        "coordinates": null
                      },
                      "originAddress": null,
                      "saleChannel": null,
                      "project": null,
                      "lead": null,
                      "provider": {
                        "id": 19,
                        "reference": null,
                        "name": "Carlos",
                        "lastname": "Muñoz",
                        "email": "carlos.munoz@example.com",
                        "phone": "+56972345678",
                        "identificationNumber": null,
                        "assignedTo": null
                      },
                      "bookingBundle": null,
                      "price": 0,
                      "cost": 0,
                      "bookingAddOns": [],
                      "products": [
                        {
                          "id": 5,
                          "name": "Water heater 80L",
                          "sku": "WH-80L",
                          "productType": "product",
                          "quantity": 1,
                          "serialNumber": "SN-0001-A",
                          "pricing": {
                            "price": 39999,
                            "cost": 25000,
                            "currency": {
                              "id": 3,
                              "name": "MXN",
                              "symbol": "$"
                            }
                          }
                        }
                      ],
                      "incidents": [],
                      "alerts": [],
                      "notes": [],
                      "dynamicFormSnapshotFields": []
                    }
                  ],
                  "workOrders": [
                    {
                      "id": 990005,
                      "createdDate": "2026-07-08T13:40:30.755Z",
                      "service": {
                        "id": 2,
                        "name": "General inspection"
                      },
                      "provider": {
                        "id": 9,
                        "reference": "PROV-001",
                        "name": "Ava",
                        "lastname": "Provider",
                        "email": "ava.provider@example.com",
                        "phone": null,
                        "identificationNumber": null,
                        "assignedTo": null
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/acquisition": {
      "post": {
        "operationId": "acquisitionCreateAcquisition",
        "summary": "Create acquisition",
        "description": "### **Purpose**\n\nCreates an **acquisition** in Sodtrack from an external system, together with its items (products, product units, or extended warranties) and an associated customer.\n\nA single request can carry multiple items. For each item you indicate how to resolve it (`sku`, `serialNumber`, or `warrantyReference`) and the reference value. Sodtrack resolves each item against its product catalog and registers the acquisition.\n\nThe customer is resolved automatically: if a matching customer already exists it is reused; otherwise a new one is created.\n\nOptionally, the request can attach **dynamic form** responses (at customer, acquisition, and/or item level), attribute the acquisition to a **sale channel**, and trigger the creation of a **work order** for a given service variant.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | Sodtrack inbound integration API key. |\n\nThe endpoint is restricted to Sodtrack's private integration network. Requests from unauthorized origins are rejected.\n\n* * *\n\n### **Field Definitions**\n\n#### 🧾 **Acquisition**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `reference` | `string` | ✅ | Your unique reference for this acquisition. Must be non-empty and unique; reusing it returns `409 Conflict`. |\n| `acquisitionDate` | `string (date)` | ✅ | Acquisition date. ISO format, e.g. `\"2026-06-07\"` or a full ISO datetime. |\n| `relatedAcquisitionReference` | `string` | ❌ | Reference of a previously created acquisition to relate this one to. |\n| `serviceVariantReferenceTriggered` | `string` | ❌ | When sent, Sodtrack also creates a work order for the service variant with this external reference. See _Work order trigger_. |\n\n#### 🧍 **Customer** (`customer`)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customer.name` | `string` | ✅ | Customer first name. |\n| `customer.lastName` | `string` | ❌ | Customer last name. |\n| `customer.email` | `string` | ❌ | Customer email. Used to match an existing customer. Recommended to avoid duplicates; if omitted a temporary email is generated. |\n| `customer.reference` | `string` | ❌ | Your external reference for the customer. Used to match an existing customer when email does not match. |\n| `customer.phoneType` | `string` | ❌ | One of: `\"MOBILE\"`, `\"HOME\"`, `\"WORK\"`. |\n| `customer.phoneNumber` | `string` | ❌ | Customer phone number. |\n| `customer.identificationType` | `string` | ❌ | One of: `\"PASSPORT\"`, `\"DRIVER_LICENSE\"`, `\"NATIONAL_ID\"`, `\"TAX_ID\"`, `\"OTHER\"`. |\n| `customer.identificationNumber` | `string` | ❌ | Customer identification number. |\n| `customer.identificationNumberCountry` | `string` | ❌ | Country of the identification number. |\n| `customer.dynamicForms` | `array` | ❌ | Dynamic form responses attached to the customer. See _Dynamic forms_. |\n\n#### 📦 **Items** (`items[]`)\n\nAt least one item is required.\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `items[].item.type` | `string` | ✅ | How to resolve the item. One of: `\"sku\"` (product), `\"serialNumber\"` (product unit), `\"warrantyReference\"` (extended warranty). |\n| `items[].item.value` | `string` | ✅ | The reference value matching `type` (the product SKU, the product unit serial number, or the warranty external reference). |\n| `items[].quantity` | `number` | ❌ | Quantity for the item. Defaults to `1`. |\n| `items[].dynamicForms` | `array` | ❌ | Dynamic form responses attached to this item. See _Dynamic forms_. |\n\n#### 📣 **Sale channel** (`saleChannel`)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `saleChannel` | `object` | ❌ | Sale channel the acquisition is attributed to. If omitted, the acquisition is created without one. |\n| `saleChannel.type` | `string` | ✅ when object sent | How to identify the sale channel. One of: `\"reference\"` (look it up by its string reference), `\"id\"` (the numeric primary key). |\n| `saleChannel.value` | `string` | ✅ when object sent | The value used to identify the sale channel (the reference string, or the numeric id as string). An unknown or invalid channel is rejected with `400 Bad Request` (`INVALID_SALES_CHANNEL`). |\n\n#### 📝 **Dynamic forms** (`dynamicForms[]`)\n\nAcquisition-level dynamic forms are sent in the top-level `dynamicForms`. The same shape applies to `customer.dynamicForms` and `items[].dynamicForms`.\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `dynamicForms[].formReference` | `string` | ✅ | Reference of an existing, active dynamic form. |\n| `dynamicForms[].values` | `array` | ✅ | Field responses for the form. |\n| `dynamicForms[].values[].fieldReference` | `string` | ✅ | Reference of a field defined in the form. |\n| `dynamicForms[].values[].value` | `string` | ❌ | Value for that field. |\n| `dynamicForms[].values[].secondaryValue` | `string` | ❌ | Secondary answer for composite fields (e.g. currency amount). Free-form string. |\n\n* * *\n\n### **Example Request**\n\nComplete example (customer + item-level and acquisition-level dynamic forms + sale channel + work order trigger):\n\n```json\n{\n  \"reference\": \"ACQ-EXT-1001\",\n  \"acquisitionDate\": \"2026-06-07\",\n  \"serviceVariantReferenceTriggered\": \"SERVICE-MOTO-10000KM\",\n  \"customer\": {\n    \"name\": \"Lucía\",\n    \"lastName\": \"Fernández\",\n    \"email\": \"lucia.fernandez@example.com\",\n    \"phoneType\": \"MOBILE\",\n    \"phoneNumber\": \"+5491150000001\",\n    \"identificationType\": \"NATIONAL_ID\",\n    \"identificationNumber\": \"30111222\",\n    \"identificationNumberCountry\": \"AR\",\n    \"reference\": \"EXT-CUST-1001\",\n    \"dynamicForms\": [\n      {\n        \"formReference\": \"FORM-CUSTOMER\",\n        \"values\": [{ \"fieldReference\": \"customer_segment\", \"value\": \"Premium\" }]\n      }\n    ]\n  },\n  \"items\": [\n    {\n      \"item\": { \"type\": \"serialNumber\", \"value\": \"BOX150-CHS-2402\" },\n      \"quantity\": 1,\n      \"dynamicForms\": [\n        {\n          \"formReference\": \"FORM-ACQ-ITEM\",\n          \"values\": [{ \"fieldReference\": \"item_condition\", \"value\": \"nuevo\" }]\n        }\n      ]\n    }\n  ],\n  \"saleChannel\": { \"type\": \"reference\", \"value\": \"SALES-CHANNEL-WEB\" },\n  \"dynamicForms\": [\n    {\n      \"formReference\": \"FORM-ACQUISITION\",\n      \"values\": [{ \"fieldReference\": \"acquisition_channel\", \"value\": \"web\" }]\n    }\n  ]\n}\n\n```\n\nMinimal example:\n\n```json\n{\n  \"reference\": \"ACQ-EXT-1002\",\n  \"acquisitionDate\": \"2026-06-07\",\n  \"customer\": {\n    \"name\": \"Diego\",\n    \"email\": \"diego.pereyra@example.com\"\n  },\n  \"items\": [\n    { \"item\": { \"type\": \"sku\", \"value\": \"MOTO-HND-CG125\" }, \"quantity\": 1 }\n  ]\n}\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"id\": 73457,\n  \"customer\": {\n    \"id\": 32813,\n    \"name\": \"Lucía\",\n    \"lastname\": \"Fernández\",\n    \"email\": \"lucia.fernandez@example.com\",\n    \"phone\": \"+5491150000001\",\n    \"reference\": \"EXT-CUST-1001\"\n  },\n  \"acquisitionDate\": \"2026-06-07T00:00:00.000Z\",\n  \"items\": [\n    {\n      \"id\": 89250,\n      \"itemType\": \"serialNumber\",\n      \"product\": { \"id\": 6, \"sku\": \"MOTO-BAJ-BOX150\", \"name\": \"Bajaj Boxer 150\" },\n      \"productUnit\": { \"id\": 41020, \"serialNumber\": \"BOX150-CHS-2402\" }\n    }\n  ]\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sodtrack acquisition identifier. |\n| `customer.id` | `number` | Sodtrack customer identifier. |\n| `customer.name` | `string` | Customer first name. |\n| `customer.lastname` | `string` | Customer last name. |\n| `customer.email` | `string` | Customer email. |\n| `customer.phone` | `string` | Customer phone. |\n| `customer.reference` | `string` | Customer external reference. |\n| `acquisitionDate` | `string (date-time)` | Acquisition date. |\n| `items[].id` | `number` | Sodtrack acquisition item identifier. |\n| `items[].itemType` | `string` | Resolved item type. |\n| `items[].product` | `object` | Resolved product (`id`, `sku`, `name`). Present when the item resolves to a product. |\n| `items[].productUnit` | `object` | Resolved product unit (`id`, `serialNumber`). Present when the item is a product unit. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | — | Missing or invalid fields, an invalid/unknown dynamic form, or an item that cannot be resolved (e.g. product, product unit, or warranty not found). |\n| `400 Bad Request` | `INVALID_SALES_CHANNEL` | The sale channel could not be resolved from `saleChannel`. |\n| `401 Unauthorized` | — | API key missing or invalid. |\n| `403 Forbidden` | — | Origin not authorized for the inbound integration network. |\n| `409 Conflict` | `ACQUISITION_ALREADY_EXISTS` | An acquisition already exists for the given `reference`. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Customer resolution\n\nSodtrack resolves the customer before creating the acquisition:\n\n| Scenario | Behavior |\n| --- | --- |\n| `customer.email` matches an existing customer | The existing customer is reused. |\n| No email match but `customer.reference` matches | The existing customer is reused. |\n| No match | A new customer is created (a temporary email is generated when none is provided). |\n\nWhen an existing customer is reused, the remaining `customer.*` fields are **not** updated.\n\n## Dynamic forms\n\nDynamic forms can be attached at three levels: `customer`, the acquisition (top-level `dynamicForms`), and each item (`items[].dynamicForms`).\n\n| Scenario | Behavior |\n| --- | --- |\n| All sent forms are valid | The acquisition is created and the form responses are stored. |\n| A form is invalid (unknown `formReference`, or a value that does not satisfy the form) | The request is rejected with `400 Bad Request` and **nothing is created**. Forms are validated before the acquisition is created. |\n\n## Item resolution\n\nEach item is resolved against the Sodtrack product catalog using `item.type` and `item.value`:\n\n| `item.type` | `item.value` must be | Resolves to |\n| --- | --- | --- |\n| `sku` | a product SKU | a product |\n| `serialNumber` | a product unit serial number | a product unit (and its product) |\n| `warrantyReference` | a warranty external reference | an extended warranty (resolved against the products in the same request) |\n\nIf any item cannot be resolved, the request is rejected with `400 Bad Request`.\n\n## Work order trigger\n\nWhen `serviceVariantReferenceTriggered` is sent, Sodtrack additionally creates a work order:\n\n-   Same customer as the acquisition.\n    \n-   One work order item per acquisition item that resolved to a product (carrying the product unit when present).\n    \n-   Built on a **best-effort** basis: if the service variant reference does not exist, or no acquisition item resolved to a product, the work order is **not** created and the acquisition is still returned successfully.\n    \n\n## Idempotency\n\n`reference` must be unique. Re-sending the same `reference` returns `409 Conflict`.",
        "tags": [
          "Acquisition"
        ],
        "parameters": [],
        "responses": {
          "400": {
            "description": "Missing or invalid fields, an invalid/unknown dynamic form, or an item that cannot be resolved (e.g. product, product unit, or warranty not found)."
          },
          "401": {
            "description": "API key missing or invalid."
          },
          "403": {
            "description": "Origin not authorized for the inbound integration network."
          },
          "409": {
            "description": "ACQUISITION_ALREADY_EXISTS — An acquisition already exists for the given reference."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "default": {
            "description": "Create acquisition",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "customer": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "name": {
                          "type": "string"
                        },
                        "lastname": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "phone": {
                          "type": "string"
                        },
                        "reference": {
                          "type": "string"
                        }
                      }
                    },
                    "acquisitionDate": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "itemType": {
                            "type": "string"
                          },
                          "product": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "sku": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "productUnit": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "serialNumber": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "id": 73457,
                  "customer": {
                    "id": 32813,
                    "name": "Lucía",
                    "lastname": "Fernández",
                    "email": "lucia.fernandez@example.com",
                    "phone": "+5491150000001",
                    "reference": "EXT-CUST-1001"
                  },
                  "acquisitionDate": "2026-06-07T00:00:00.000Z",
                  "items": [
                    {
                      "id": 89250,
                      "itemType": "serialNumber",
                      "product": {
                        "id": 6,
                        "sku": "MOTO-BAJ-BOX150",
                        "name": "Bajaj Boxer 150"
                      },
                      "productUnit": {
                        "id": 41020,
                        "serialNumber": "BOX150-CHS-2402"
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/transaction": {
      "post": {
        "operationId": "transactionsCreateTransaction",
        "summary": "Create Transaction",
        "description": "### **Purpose**\n\nCreates a transaction (payment or refund) associated with a booking. Optionally breaks down amounts by variant (main service) and addons. The shopping cart is determined from the specified booking.\n\n### **Field Definitions**\n\n#### Booking\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| booking | object | ✅ | Object that identifies the booking |\n| booking.type | enum | ✅ | Identifier: bookingId, bookingReference, shoppingCartId, subscriptionId |\n| booking.value | string | ✅ | Value by type (numeric ID or reference) |\n| booking.variant | object | ❌ | Variant information to specify if booking referene is used |\n| booking.variant.type | string | ✅ | Identifier: variantId or variantSku |\n| booking.variant.value | string | ✅ | Value by type (numeric ID or reference) |\n\n#### Transaction Detail\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| transactionDetail | object | ❌ | Breakdown by variant and addons |\n| transactionDetail.variant | object | ✅ | Variant details |\n| transactionDetail.variant.ammount | number | ✅ | Variant amount |\n| transactionDetail.variant.quantityAdjustment | number | ❌ | Variant quantity adjustment |\n| transactionDetail.addon | array | ❌ | Addons array |\n| transactionDetail.addon\\[\\].type | enum | ✅ | addonId or addonReference |\n| transactionDetail.addon\\[\\].value | string | ✅ | Addon ID or SKU |\n| transactionDetail.addon\\[\\].ammount | number | ❌ | Addon amount |\n| transactionDetail.addon\\[\\].quantityAdjustment | number | ❌ | Addon quantity adjustment |\n\n#### Metadata\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| type | enum | ✅ | Transaction type: payment or refund |\n| reference | string | ❌ | External reference |\n| extraInfo | string | ❌ | Additional info |\n| cancelBookingIfTotallyRefunded | boolean | ❌ | Defines cancel policy for total refund of a booking |\n\n### **Response Example**\n\n```json\n{\n    \"id\": 346,\n    \"type\": \"refund\",\n    \"reference\": \"NR-00000000003\",\n    \"amount\": 5000\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack transaction ID. |\n| `type` | `number` | Transaction type: payment or refund |\n| `reference` | `string` | External reference |\n| `ammount` | `number` | Total transaction amount |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid. |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n### **Business Logic Notes**\n\n-   If transaction type is refund and cancelBookingIfTotallyRefunded is set to true:\n    \n    -   If the refund is for the total payment amount of the booking, it will cancel the booking after the transaction creation.\n-   The quantityAdjustment only works for refund type transactions with the following constraints:\n    \n    -   The quantityAdjustment for the booking's variant, has always to be less than the quantity of the booking.\n        \n    -   The quantityAdjustmen for an addon has to be equal or less than the quantity of that addon in the booking.\n        \n-   Constraints:\n    \n    -   A payment cannot exeed the amount that remains unpaid for each element; variant or addon.\n        \n    -   In order to post a refund, there should exist a previous payment transaction.\n        \n        -   The amount of a refund cannot exceed the already payed amount for each instance.\n    -   The quantity of a booking variant cannot be 0 as a result of the transaction.\n        \n    -   The quantity of a booking addon can go to 0, eliminating the relation between addon and booking.",
        "tags": [
          "Transactions"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": "{\n    \"type\": \"string\", // Possible values: payment | refund\n    \"extra_info\": \"string\", // ej. \"Payment from client in store\"\n    \"reference\": \"string\", // external reference, like: invoice number, credit note number or others.\n    \"booking\": {\n        \"type\": \"string\", // bookingReference | bookingId\n        \"value\": \"string\", // value of the type\n        \"variant\": {\n            \"type\": \"string\",\n            \"value\": \"string\"\n        }\n    },\n    \"transactionDetail\": {\n        \"variant\": {\n            \"quantityAdjustment\": \"number\", //Optional. Only applies to refund type of the transaction. A decimal number greater than 0 less or equals than the total quantity of the variant of the booking  \n            \"amount\": \"number\" //decimal number greater than 0 less or equals than the total price of the variant\n        },\n        \"addon\": [\n            {\n                \"type\": \"string\", // Possible values: addonId | addonReference\n                \"value\": \"string\", // value of the type\n                \"quantityAdjustment\": \"number\", //Optional. Only applies to refund type of the transaction. A decimal number greater than 0 less or equals than the total quantity of the addon of the booking  \n                \"amount\": \"number\" //decimal number greater than 0 less or equals than the total price of the addon\n            }\n        ]\n    },\n    \"cancelBookingIfTotallyRefunded\": \"boolean\" // If transaction type is refund and is a total refund, the booking will be canceled after the refund creation.\n}"
            }
          }
        },
        "responses": {
          "400": {
            "description": "InvalidParameters — One or more required fields are missing or invalid."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "default": {
            "description": "Refund"
          }
        }
      }
    },
    "/api/integration/payment-request/change-status": {
      "patch": {
        "operationId": "paymentRequestsChangeStatus",
        "summary": "Change Status",
        "description": "## General Description\n\nThis endpoint updates the status of a payment request. The payment request can be identified by its internal ID or by its external reference. It is intended for use by external integration systems to sync payment state (e.g. mark as paid or cancelled).\n\n* * *\n\n## Field Definitions\n\n### Request Body:\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| paymentRequest | PaymentRequestIdentifierDto | Yes | Object identifying the payment request by ID or reference. |\n| status | enum | Yes | New status. Must be one of: pending, paid, cancelled. |\n\n### PaymentRequestIdentifierDto\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| type | enum | Yes | Identifier type. Must be one of: paymentRequestId or paymentRequestReference. |\n| value | string | Yes | The payment request ID (if type is paymentRequestId) or reference (if type is paymentRequestReference). |\n\n* * *\n\n## Example Request\n\n```json\n{\n  \"paymentRequest\": {\n    \"type\": \"paymentRequestId\",\n    \"value\": \"342\"\n  },\n  \"status\": \"cancelled\"\n}\n\n```\n\nOr by reference:\n\n```json\n{\n  \"paymentRequest\": {\n    \"type\": \"paymentRequestId\",\n    \"value\": \"PAY-EXT-001\"\n  },\n  \"status\": \"cancelled\"\n}\n\n```\n\n## Example Response\n\nSuccess (200 OK): Returns the updated payment request.\n\n```json\n{\n  \"id\": \"342\",\n  \"status\": \"paid\",\n  \"entityType\": \"lead\",\n  \"entityTypeId\": 123,\n  \"amount\": 150.50,\n  \"description\": \"Lead payment\",\n  \"reference\": \"PAY-EXT-001\",\n  \"createdDate\": \"2025-02-01T10:00:00.000Z\",\n  \"updatedDate\": \"2025-02-12T14:30:00.000Z\",\n  \"currency\": {\n    \"id\": \"8\",\n    \"code\": \"USD\",\n    \"symbol\": \"$\"\n  }\n}\n\n```\n\n## Example Error Response\n\nPayment request not found (404 Not Found):\n\n```json\n{\n  \"statusCode\": 404,\n  \"message\": \"PAYMENT_REQUEST_NOT_FOUND\",\n  \"error\": \"Not Found\"\n}\n\n```",
        "tags": [
          "Payment requests"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Change Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "entityType": {
                      "type": "string"
                    },
                    "entityTypeId": {
                      "type": "integer"
                    },
                    "amount": {
                      "type": "number"
                    },
                    "description": {
                      "type": "string"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "createdDate": {
                      "type": "string"
                    },
                    "updatedDate": {
                      "type": "string"
                    },
                    "currency": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "symbol": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "id": "342",
                  "status": "paid",
                  "entityType": "lead",
                  "entityTypeId": 123,
                  "amount": 150.5,
                  "description": "Lead payment",
                  "reference": "PAY-EXT-001",
                  "createdDate": "2025-02-01T10:00:00.000Z",
                  "updatedDate": "2025-02-12T14:30:00.000Z",
                  "currency": {
                    "id": "8",
                    "code": "USD",
                    "symbol": "$"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/integration/provider": {
      "post": {
        "operationId": "usersCreateProvider",
        "summary": "Create provider",
        "description": "-   `basicInformation (object) - required`**`:`** Objetc that represent the main information of the user\n    \n    -   `name (string) - required`: Name of the technician or network\n        \n    -   `lastName (string) - required`: Lastname of the technician or network\n        \n    -   `email (string) - required`: Access email for the technician or network to the platforms\n        \n    -   `phoneNumber (string) - required`: Phone number\n        \n    -   `identificationNumber (string) - required`: Fiscal number of the the technician or network\n        \n    -   `identificationNumberCountry (string) - required`: ISO-2 country string\n        \n-   `isCompany (boolean) - required`: true if it is a network false if it is a single technician.\n    \n-   `workOnHolidays (boolean)`: If the avaialbility algorithm should take into account the general holidays as holidays for this provider\n    \n-   `isMainProviderEligible (boolean)`: Select if the technitian is elleggible to be main provider of projects\n    \n-   `isLeadAssignmentEligible (boolean)`: Select if the technitian is elleggible to be main provider of leads.\n    \n-   `reference (string)`: External reference of the provider, generally the identifier of the provider in your integrated platform",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "dev.api.cl.sodtrack.sodtrack.com"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "basicInformation": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      },
                      "identificationNumber": {
                        "type": "string"
                      },
                      "identificationNumberCountry": {
                        "type": "string"
                      }
                    }
                  },
                  "reference": {
                    "type": "string"
                  },
                  "workOnHolidays": {
                    "type": "boolean"
                  },
                  "isCompany": {
                    "type": "boolean"
                  },
                  "isMainProviderEligible": {
                    "type": "boolean"
                  },
                  "isLeadAssignmentEligible": {
                    "type": "boolean"
                  }
                }
              },
              "example": {
                "basicInformation": {
                  "name": "John",
                  "lastName": "Contractor",
                  "email": "johncontractor@gmail.com",
                  "phoneNumber": "+56978993325",
                  "identificationNumber": "19081637-0",
                  "identificationNumberCountry": "CL"
                },
                "reference": "A244923DSR",
                "workOnHolidays": false,
                "isCompany": true,
                "isMainProviderEligible": true,
                "isLeadAssignmentEligible": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Create provider",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "status": {
                      "type": "string"
                    },
                    "reference": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": 90,
                  "status": "created",
                  "reference": "A244923DS11"
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/customer": {
      "get": {
        "operationId": "usersGetCustomers",
        "summary": "Get customers",
        "description": "### **Purpose**\n\nReturns a **paginated** list of **customers**, with the core fields needed to identify and reconcile a customer against your own records.\n\nFilters can be **combined freely**: every filter you send is applied together, and a customer is returned only when it satisfies **all** of them. Customers can be looked up directly (by Sodtrack id, external reference or identification number) or indirectly through their bookings.\n\nThis endpoint is designed to **resolve and identify** customers. It does not return contact details, identity documents or addresses.\n\n* * *\n\n#### 🔎 Query parameters\n\n| Parameter | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | `number` | ❌ | Filter by Sodtrack customer id. Must be a positive integer. |\n| `reference` | `string` | ❌ | Filter by customer external reference. Exact match. |\n| `identificationNumber` | `string` | ❌ | Filter by customer identification number. Separators such as dots and dashes are ignored, so `\"12.345.678-9\"` and `\"123456789\"` match the same customer. |\n| `bookingId` | `number` | ❌ | Return the customers linked to the booking with this id. Must be a positive integer. |\n| `bookingReference` | `string` | ❌ | Return the customers linked to bookings with this reference. |\n| `pageSize` | `number` | ❌ | Number of results per page. Min `1`, max `50`. Default **`10`**. |\n| `pageNumber` | `number` | ❌ | Page index (**1-based**). Default **`1`**. |\n\n> All filters are optional and can be combined. Sending none returns the paginated list of all customers, ordered by `id` descending.\n\n> Filters sent as empty or whitespace-only strings are ignored, exactly as if they had not been sent. Unrecognized query parameters are ignored.\n\n* * *\n\n### **Example Requests**\n\nLook up a customer by identification number:\n\n```\nGET /api/integration/customer?identificationNumber=12.345.678-9\n\n```\n\nCombine filters to confirm that a reference and an identification number belong to the same customer:\n\n```\nGET /api/integration/customer?reference=EXT-CUSTOMER-REF-001&identificationNumber=123456789\n\n```\n\nFind the customers behind a booking reference:\n\n```\nGET /api/integration/customer?bookingReference=EXT-BOOKING-REF-001\n\n```\n\nPaginate the full customer list:\n\n```\nGET /api/integration/customer?pageSize=25&pageNumber=2\n\n```\n\n### **Response Example**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": 2001,\n      \"reference\": \"EXT-CUSTOMER-REF-001\",\n      \"name\": \"María\",\n      \"lastname\": \"García\",\n      \"createdDate\": \"2024-06-01T10:00:00.000Z\"\n    },\n    {\n      \"id\": 1987,\n      \"reference\": null,\n      \"name\": \"Comercial Andes\",\n      \"lastname\": null,\n      \"createdDate\": \"2024-05-18T08:22:41.000Z\"\n    }\n  ],\n  \"metadata\": {\n    \"count\": 2,\n    \"pageNumber\": 1,\n    \"pageSize\": 10,\n    \"totalPages\": 1\n  }\n}\n\n```\n\n#### **Customer item (****`data[]`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Sodtrack customer id. |\n| `reference` | `string` | `null` |\n| `name` | `string` | `null` |\n| `lastname` | `string` | `null` |\n| `createdDate` | `string` (ISO 8601) | Customer record creation timestamp. |\n\n#### **Pagination (****`metadata`****)**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `count` | `number` | Total number of customers matching the filters, across all pages. |\n| `pageNumber` | `number` | Current page (1-based). |\n| `pageSize` | `number` | Page size used for this response. |\n| `totalPages` | `number` | Total pages for the current filters and `pageSize`. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | Validation error | A query parameter has an invalid value: `id` or `bookingId` is not a positive integer, `pageSize` is outside `1`–`50`, or `pageNumber` is below `1`. The response body lists the offending parameters. |\n| `401 Unauthorized` | — | `x-api-key` is missing or invalid, or the request does not originate from an authorized network. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\nWhen the filters match no customers, the request still succeeds: `data` is `[]` and `metadata.count` is `0`.\n\n* * *\n\n# Business Rules & Constraints\n\n## Combining filters\n\nEvery filter present in the request is applied together, and only customers satisfying **all** of them are returned.\n\n| Filters sent | Behavior |\n| --- | --- |\n| _(none)_ | All customers, paginated, ordered by `id` descending. |\n| One filter | Customers matching that filter. |\n| Several filters | Only customers matching every filter at once. |\n\nSeveral filters reach the same customer through different paths: `id`, `reference` and `identificationNumber` point at the customer directly, while `bookingId` and `bookingReference` reach it through its bookings. Combining them is a valid way to **confirm** that a customer matches more than one criterion.\n\nPointing two filters at different customers is not an error. The request succeeds and returns an empty page, because no single customer satisfies both conditions.\n\n## Identification number matching\n\nThe identification number is matched after removing separator characters from the value you send, so punctuation formatting does not affect the result.\n\n| Value sent | Matches stored value |\n| --- | --- |\n| `12.345.678-9` | `123456789` |\n| `12345678-9` | `123456789` |\n| `123456789` | `123456789` |\n\nSpaces are **not** removed. Send the identification number without internal spaces, or it will not match.\n\nMatching is exact after this normalization: partial identification numbers return no results.\n\n## Booking-based filtering\n\n`bookingId` and `bookingReference` select bookings first, and then return the customers those bookings belong to.\n\n| Filters sent | Behavior |\n| --- | --- |\n| `bookingId` | Customers of the booking with that id. |\n| `bookingReference` | Distinct customers of all bookings sharing that reference. |\n| Both | Only bookings matching **both** the id and the reference are considered. |\n\nIf no booking matches, or the matching bookings have no customer associated, the response is an empty page.\n\n## Pagination\n\n-   `pageNumber` is **1-based**: the first page is `1`.\n    \n-   Default `pageSize` is **10**, maximum is **50**.\n    \n-   `count` reflects all customers matching the filters, not only those on the current page.\n    \n-   Results are always ordered by `id` descending, so the most recently created customers appear first.",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Get customers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "reference": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "lastname": {
                            "type": "string"
                          },
                          "email": {
                            "type": "string"
                          },
                          "phone": {
                            "type": "string"
                          },
                          "identificationNumber": {
                            "type": "string"
                          },
                          "identificationNumberCountry": {
                            "type": "string"
                          },
                          "createdDate": {
                            "type": "string"
                          },
                          "addresses": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "formattedAddress": {
                                  "type": "string"
                                },
                                "coordinates": {
                                  "type": "object",
                                  "properties": {
                                    "lat": {
                                      "type": "number"
                                    },
                                    "lng": {
                                      "type": "number"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "metadata": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "pageNumber": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 2001,
                      "reference": "EXT-CUSTOMER-REF-001",
                      "name": "María",
                      "lastname": "García",
                      "email": "maria.garcia@example.com",
                      "phone": "+56912345678",
                      "identificationNumber": "12345678-9",
                      "identificationNumberCountry": "CL",
                      "createdDate": "2024-06-01T10:00:00.000Z",
                      "addresses": [
                        {
                          "formattedAddress": "Av. Providencia 1234, Santiago, Chile",
                          "coordinates": {
                            "lat": -33.43324794409109,
                            "lng": -70.58645659063548
                          }
                        }
                      ]
                    }
                  ],
                  "metadata": {
                    "count": 1,
                    "pageSize": 10,
                    "pageNumber": 1,
                    "totalPages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — A query parameter has an invalid value: id or bookingId is not a positive integer, pageSize is outside 1–50, or pageNumber is below 1. The response body lists the offending parameters."
          },
          "401": {
            "description": "x-api-key is missing or invalid, or the request does not originate from an authorized network."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/customer/{customerId}/product-units": {
      "get": {
        "operationId": "usersGetProductUnitsByCustomer",
        "summary": "Get Product Units by Customer",
        "description": "### **Purpose**\n\nReturns the **product units currently held by a customer**, as a paginated list.\n\nThe customer is identified by its Sodtrack id in the path. To resolve that id from your own data, search the customer first with `GET /api/integration/customer/v2` (by `reference`, `phoneNumber`, `identificationNumber` or a booking) and take `id` from the result.\n\nSodtrack returns every product unit whose current physical location is that customer, newest first. Each unit comes with its parent product, its type (`product` or `component`), its status, and the movement that brought it to the customer, including the delivery address.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | Sodtrack inbound integration API key. |\n\nThe endpoint is restricted to Sodtrack's private integration network. Requests from unauthorized origins are rejected.\n\n* * *\n\n### **Endpoint**\n\n`GET /api/integration/customer/{customerId}/product-units`\n\n* * *\n\n### **Field Definitions**\n\n#### 🧍 **Path parameters**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customerId` | `number` | ✅ | Sodtrack customer id. Must be an integer. |\n\n#### 📄 **Pagination** (query parameters)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `pageNumber` | `number` | ❌ | 1-based page number. Defaults to `1`. |\n| `pageSize` | `number` | ❌ | Product units per page. Between `1` and `50`. Defaults to `10`. |\n\nNo other parameter is accepted; any other query parameter is ignored.\n\n* * *\n\n### **Example Request**\n\n```\nGET /api/integration/customer/32841/product-units\n```\n\nSecond page of 5 units:\n\n```\nGET /api/integration/customer/32841/product-units?pageNumber=2&pageSize=5\n```\n\n### **Response Example**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": 85,\n      \"serialNumber\": \"SN-0001-C\",\n      \"status\": \"in_use\",\n      \"type\": \"component\",\n      \"entryDate\": \"2026-08-09T00:19:48.993Z\",\n      \"cost\": null,\n      \"product\": {\n        \"id\": 28310,\n        \"name\": \"Thermostat\",\n        \"sku\": \"TH-01\"\n      },\n      \"lastMovement\": {\n        \"id\": 77,\n        \"createdDate\": \"2026-08-29T00:19:48.994Z\",\n        \"fromLocationType\": \"warehouse\",\n        \"fromId\": \"1\",\n        \"fromName\": \"Central warehouse\",\n        \"fromAddress\": null,\n        \"toLocationType\": \"customer\",\n        \"toId\": \"32841\",\n        \"toName\": \"María González\",\n        \"toAddress\": {\n          \"id\": 13,\n          \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n          \"extraInfo\": \"Floor 3, Apt B\"\n        }\n      }\n    },\n    {\n      \"id\": 83,\n      \"serialNumber\": \"SN-0001-A\",\n      \"status\": \"in_use\",\n      \"type\": \"product\",\n      \"entryDate\": \"2026-08-09T00:19:48.979Z\",\n      \"cost\": null,\n      \"product\": {\n        \"id\": 990001,\n        \"name\": \"Water heater 80L\",\n        \"sku\": \"WH-80L\"\n      },\n      \"lastMovement\": {\n        \"id\": 75,\n        \"createdDate\": \"2026-08-29T00:19:48.984Z\",\n        \"fromLocationType\": \"warehouse\",\n        \"fromId\": \"1\",\n        \"fromName\": \"Central warehouse\",\n        \"fromAddress\": null,\n        \"toLocationType\": \"customer\",\n        \"toId\": \"32841\",\n        \"toName\": \"María González\",\n        \"toAddress\": {\n          \"id\": 13,\n          \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n          \"extraInfo\": \"Floor 3, Apt B\"\n        }\n      }\n    }\n  ],\n  \"metadata\": {\n    \"count\": 2,\n    \"pageNumber\": 1,\n    \"pageSize\": 10,\n    \"totalPages\": 1\n  }\n}\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `data[]` | `array` | Product units in the page, newest first. Empty when the customer holds none. |\n| `data[].id` | `number` | Sodtrack product unit id. Use it with the product unit detail endpoint. |\n| `data[].serialNumber` | `string | null` | Serial number of the unit. |\n| `data[].status` | `string` | One of: `\"available\"`, `\"not_available\"`, `\"committed\"`, `\"in_use\"`, `\"potential_conflict\"`, `\"movement_request\"`. |\n| `data[].type` | `string` | `\"product\"` or `\"component\"`. |\n| `data[].entryDate` | `string (datetime) | null` | When the unit entered Sodtrack's inventory. |\n| `data[].cost` | `number | null` | Unit cost, when registered. |\n| `data[].product` | `object` | Parent product. |\n| `data[].product.id` | `number` | Sodtrack product id. |\n| `data[].product.name` | `string` | Product name. |\n| `data[].product.sku` | `string` | Product SKU. |\n| `data[].lastMovement` | `object | null` | Movement that brought the unit to its current location. `null` when the unit has no movement history. |\n| `data[].lastMovement.id` | `number` | Movement id. |\n| `data[].lastMovement.createdDate` | `string (datetime) | null` | When the movement happened. |\n| `data[].lastMovement.fromLocationType` | `string | null` | Origin type: `\"warehouse\"`, `\"customer\"` or `\"provider\"`. `null` for the unit's initial entry. |\n| `data[].lastMovement.fromId` | `string | null` | Id of the origin warehouse or customer, according to `fromLocationType`. |\n| `data[].lastMovement.fromName` | `string | null` | Name of the origin warehouse or customer. |\n| `data[].lastMovement.fromAddress` | `object | null` | Origin address, when the origin is a customer address. Same shape as `toAddress`. |\n| `data[].lastMovement.toLocationType` | `string` | Destination type: `\"warehouse\"`, `\"customer\"` or `\"provider\"`. |\n| `data[].lastMovement.toId` | `string` | Id of the destination warehouse or customer, according to `toLocationType`. |\n| `data[].lastMovement.toName` | `string | null` | Name of the destination warehouse or customer. |\n| `data[].lastMovement.toAddress` | `object | null` | Delivery address, when the destination is a customer address. |\n| `data[].lastMovement.toAddress.id` | `number` | Sodtrack address id. |\n| `data[].lastMovement.toAddress.formattedAddress` | `string` | Full formatted address. |\n| `data[].lastMovement.toAddress.extraInfo` | `string | null` | Additional address details (floor, apartment, notes). |\n| `metadata.count` | `number` | Total product units held by the customer, across all pages. |\n| `metadata.pageNumber` | `number` | Page returned. |\n| `metadata.pageSize` | `number` | Page size applied. |\n| `metadata.totalPages` | `number` | Total number of pages. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `Validation failed (numeric string is expected)` | `customerId` is not an integer. |\n| `400 Bad Request` | — | A pagination parameter has the wrong type or is out of range (for example `pageSize` above `50`). |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`, or the request does not come from an authorized origin. |\n| `404 Not Found` | `CUSTOMER_NOT_FOUND: {customerId}` | No customer exists with that id. |\n| `503 Service Unavailable` | `PRODUCT_MODULE_UNAVAILABLE` | Sodtrack's product inventory service could not be reached. Retry later. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## The customer must exist\n\n`customerId` must be the id of a Sodtrack customer. Unknown ids, and ids of providers, network users or other account types, are answered with `404 Not Found`. A customer that exists but holds no product unit is answered with `200 OK` and an empty `data`.\n\n## Product units are the ones currently at the customer\n\n`data` contains only the units whose current physical location is that customer. Units that were delivered and later returned to a warehouse, or moved to another customer, are not included. To see the full history of a unit use the product unit detail endpoint with `data[].id`.\n\n## Location names and addresses are resolved when possible\n\n`fromName`, `toName`, `fromAddress` and `toAddress` in `lastMovement` are resolved from the warehouse or customer referenced by the movement. If that warehouse or customer no longer exists, the name or address comes back as `null` while the raw `fromId` / `toId` is still returned.\n\n## Ordering\n\nProduct units are ordered by id, newest first.\n\n## Page boundaries\n\nA `pageNumber` beyond the last page is not an error: it returns an empty `data` with the same `metadata.count` and `metadata.totalPages`.",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Get Product Units by Customer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "serialNumber": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "entryDate": {
                            "type": "string"
                          },
                          "cost": {
                            "type": "null"
                          },
                          "product": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "sku": {
                                "type": "string"
                              }
                            }
                          },
                          "lastMovement": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "createdDate": {
                                "type": "string"
                              },
                              "fromLocationType": {
                                "type": "string"
                              },
                              "fromId": {
                                "type": "string"
                              },
                              "fromName": {
                                "type": "string"
                              },
                              "fromAddress": {
                                "type": "null"
                              },
                              "toLocationType": {
                                "type": "string"
                              },
                              "toId": {
                                "type": "string"
                              },
                              "toName": {
                                "type": "string"
                              },
                              "toAddress": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "formattedAddress": {
                                    "type": "string"
                                  },
                                  "extraInfo": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "metadata": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "pageNumber": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 85,
                      "serialNumber": "SN-0001-C",
                      "status": "in_use",
                      "type": "component",
                      "entryDate": "2026-08-09T00:19:48.993Z",
                      "cost": null,
                      "product": {
                        "id": 28310,
                        "name": "Thermostat",
                        "sku": "TH-01"
                      },
                      "lastMovement": {
                        "id": 77,
                        "createdDate": "2026-08-29T00:19:48.994Z",
                        "fromLocationType": "warehouse",
                        "fromId": "1",
                        "fromName": "Central warehouse",
                        "fromAddress": null,
                        "toLocationType": "customer",
                        "toId": "32841",
                        "toName": "María González",
                        "toAddress": {
                          "id": 13,
                          "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                          "extraInfo": "Floor 3, Apt B"
                        }
                      }
                    },
                    {
                      "id": 83,
                      "serialNumber": "SN-0001-A",
                      "status": "in_use",
                      "type": "product",
                      "entryDate": "2026-08-09T00:19:48.979Z",
                      "cost": null,
                      "product": {
                        "id": 990001,
                        "name": "Water heater 80L",
                        "sku": "WH-80L"
                      },
                      "lastMovement": {
                        "id": 75,
                        "createdDate": "2026-08-29T00:19:48.984Z",
                        "fromLocationType": "warehouse",
                        "fromId": "1",
                        "fromName": "Central warehouse",
                        "fromAddress": null,
                        "toLocationType": "customer",
                        "toId": "32841",
                        "toName": "María González",
                        "toAddress": {
                          "id": 13,
                          "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                          "extraInfo": "Floor 3, Apt B"
                        }
                      }
                    }
                  ],
                  "metadata": {
                    "count": 2,
                    "pageNumber": 1,
                    "pageSize": 10,
                    "totalPages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (numeric string is expected) — customerId is not an integer."
          },
          "401": {
            "description": "Missing or invalid x-api-key, or the request does not come from an authorized origin."
          },
          "404": {
            "description": "CUSTOMER_NOT_FOUND: {customerId} — No customer exists with that id."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          },
          "503": {
            "description": "PRODUCT_MODULE_UNAVAILABLE — Sodtrack's product inventory service could not be reached. Retry later."
          }
        }
      }
    },
    "/api/integration/customer/{customerId}/bookings": {
      "get": {
        "operationId": "usersGetBookingsByCustomer",
        "summary": "Get Bookings By Customer",
        "description": "### **Purpose**\n\nReturns the **bookings of a customer**, as a paginated list.\n\nThe customer is identified by its Sodtrack id in the path. To resolve that id from your own data, search the customer first with `GET /api/integration/customer/v2` (by `reference`, `phoneNumber`, `identificationNumber` or a booking) and take `id` from the result.\n\nSodtrack returns every booking the customer owns, newest first. Each booking is returned in full, in the same shape as the booking search and detail endpoints: status, dates, service, variant, category, addresses, provider, products, add-ons, incidents, alerts, notes and dynamic form answers.\n\n* * *\n\n### **Authentication**\n\n| Header | Required | Description |\n| --- | --- | --- |\n| `x-api-key` | ✅ | Sodtrack inbound integration API key. |\n\nThe endpoint is restricted to Sodtrack's private integration network. Requests from unauthorized origins are rejected.\n\n* * *\n\n### **Endpoint**\n\n`GET /api/integration/customer/{customerId}/bookings`\n\n* * *\n\n### **Field Definitions**\n\n#### 🧍 **Path parameters**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `customerId` | `number` | ✅ | Sodtrack customer id. Must be an integer. |\n\n#### 📄 **Pagination** (query parameters)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `pageNumber` | `number` | ❌ | 1-based page number. Defaults to `1`. |\n| `pageSize` | `number` | ❌ | Bookings per page. Between `1` and `50`. Defaults to `10`. |\n\nNo other parameter is accepted; any other query parameter is ignored.\n\n* * *\n\n### **Example Request**\n\n```\nGET /api/integration/customer/32841/bookings\n```\n\nSecond page of 5 bookings:\n\n```\nGET /api/integration/customer/32841/bookings?pageNumber=2&pageSize=5\n```\n\n### **Response Example**\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": 13,\n      \"reference\": \"BK-2026-0456\",\n      \"status\": \"accepted\",\n      \"scheduledDate\": \"2026-08-26T04:22:29.911Z\",\n      \"quantity\": 1,\n      \"totalDurationMinutes\": 60,\n      \"doneDate\": null,\n      \"createdDate\": \"2026-08-26T04:22:29.911Z\",\n      \"customer\": {\n        \"id\": 32841,\n        \"reference\": \"CUST-00123\"\n      },\n      \"stakeholder\": null,\n      \"service\": {\n        \"id\": 1,\n        \"name\": \"Water heater installation\"\n      },\n      \"variant\": {\n        \"id\": 1,\n        \"name\": \"Standard installation\",\n        \"type\": \"execution\",\n        \"skus\": []\n      },\n      \"category\": {\n        \"id\": 1,\n        \"name\": \"Installations\"\n      },\n      \"address\": {\n        \"formattedAddress\": \"Av. Corrientes 1234, Buenos Aires\",\n        \"coordinates\": null\n      },\n      \"originAddress\": null,\n      \"saleChannel\": null,\n      \"project\": null,\n      \"lead\": null,\n      \"provider\": {\n        \"id\": 19,\n        \"reference\": null,\n        \"name\": \"Carlos\",\n        \"lastname\": \"Muñoz\",\n        \"email\": \"carlos.munoz@example.com\",\n        \"phone\": \"+56972345678\",\n        \"identificationNumber\": null,\n        \"assignedTo\": null\n      },\n      \"bookingBundle\": null,\n      \"price\": 0,\n      \"cost\": 0,\n      \"bookingAddOns\": [],\n      \"products\": [\n        {\n          \"id\": 5,\n          \"name\": \"Water heater 80L\",\n          \"sku\": \"WH-80L\",\n          \"productType\": \"product\",\n          \"quantity\": 1,\n          \"serialNumber\": \"SN-0001-A\",\n          \"pricing\": {\n            \"price\": 39999,\n            \"cost\": 25000,\n            \"currency\": {\n              \"id\": 3,\n              \"name\": \"MXN\",\n              \"symbol\": \"$\"\n            }\n          }\n        }\n      ],\n      \"incidents\": [],\n      \"alerts\": [],\n      \"notes\": [],\n      \"dynamicFormSnapshotFields\": []\n    },\n    {\n      \"id\": 12,\n      \"reference\": \"BK-2026-0455\",\n      \"status\": \"waiting_customer_to_set_date\",\n      \"scheduledDate\": null,\n      \"quantity\": 1,\n      \"totalDurationMinutes\": 60,\n      \"doneDate\": null,\n      \"createdDate\": \"2026-08-26T04:22:29.911Z\",\n      \"customer\": {\n        \"id\": 32841,\n        \"reference\": \"CUST-00123\"\n      },\n      \"stakeholder\": null,\n      \"service\": {\n        \"id\": 1,\n        \"name\": \"Water heater installation\"\n      },\n      \"variant\": {\n        \"id\": 1,\n        \"name\": \"Standard installation\",\n        \"type\": \"execution\",\n        \"skus\": []\n      },\n      \"category\": {\n        \"id\": 1,\n        \"name\": \"Installations\"\n      },\n      \"address\": {\n        \"formattedAddress\": \"Calle Falsa 123, Buenos Aires\",\n        \"coordinates\": null\n      },\n      \"originAddress\": null,\n      \"saleChannel\": null,\n      \"project\": null,\n      \"lead\": null,\n      \"provider\": null,\n      \"bookingBundle\": null,\n      \"price\": 0,\n      \"cost\": 0,\n      \"bookingAddOns\": [],\n      \"products\": [],\n      \"incidents\": [],\n      \"alerts\": [],\n      \"notes\": [],\n      \"dynamicFormSnapshotFields\": []\n    }\n  ],\n  \"metadata\": {\n    \"count\": 2,\n    \"pageNumber\": 1,\n    \"pageSize\": 10,\n    \"totalPages\": 1\n  }\n}\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `data[]` | `array` | Bookings in the page, newest first. Empty when the customer has none. |\n| `data[].id` | `number` | Sodtrack booking id. |\n| `data[].reference` | `string | null` | Your reference for the booking. |\n| `data[].status` | `string` | One of: `\"created\"`, `\"searching\"`, `\"accepted\"`, `\"on_my_way_to_origin\"`, `\"arrived_to_origin\"`, `\"on_my_way_to_destination\"`, `\"arrived_to_destination\"`, `\"left_destination\"`, `\"done\"`, `\"cancelled\"`, `\"waiting_customer_to_set_date\"`, `\"waiting_scheduling_mechanism\"`, `\"waiting_assignment_mechanism\"`, `\"waiting_provider_to_propose_date\"`, `\"waiting_customer_to_accept_proposed_date\"`. |\n| `data[].scheduledDate` | `string (datetime) | null` | Scheduled execution date. `null` until a date is set. |\n| `data[].quantity` | `number` | Quantity booked. |\n| `data[].totalDurationMinutes` | `number | null` | Total duration in minutes. |\n| `data[].doneDate` | `string (datetime) | null` | When the booking was completed. |\n| `data[].createdDate` | `string (datetime)` | When the booking was created. |\n| `data[].customer` | `object | null` | `id` and `reference` of the customer. |\n| `data[].stakeholder` | `object | null` | `id` and `reference` of the requesting party, when different from the customer. |\n| `data[].service` | `object | null` | `id` and `name` of the service. |\n| `data[].variant` | `object | null` | Service variant: `id`, `name`, `type` (`\"budget\"` or `\"execution\"`) and `skus` (product SKUs linked to the variant). |\n| `data[].category` | `object | null` | `id` and `name` of the service category. |\n| `data[].address` | `object | null` | Execution address: `formattedAddress` and `coordinates` (`lat`, `lng`, or `null`). |\n| `data[].originAddress` | `object | null` | Origin address for transport services. Same shape as `address`. |\n| `data[].saleChannel` | `object | null` | Sale channel: `id`, `name`, `reference` and `coordinates`. |\n| `data[].project` | `object | null` | `id` and `reference` of the project the booking belongs to. |\n| `data[].lead` | `object | null` | `id` and `reference` of the originating lead. |\n| `data[].provider` | `object | null` | Assigned provider: `id`, `reference`, `name`, `lastname`, `email`, `phone`, `identificationNumber` and `assignedTo` (`name`, `lastname`, `email` of the executing technician when the provider is a network, otherwise `null`). `null` while unassigned. |\n| `data[].bookingBundle` | `object | null` | When the booking is part of a bundle: `bundleHead` and `bundledBookings[]`, each with `id` and `reference`. |\n| `data[].price` | `number | null` | Booking price. |\n| `data[].cost` | `number | null` | Booking cost. |\n| `data[].bookingAddOns[]` | `array` | Add-ons: `id`, `name`, `reference`. |\n| `data[].products[]` | `array` | Products in the booking: `id`, `name`, `sku`, `productType` (`\"product\"` or `\"component\"`), `quantity`, `serialNumber` and `pricing` (`price`, `cost`, `currency` with `id`, `name`, `symbol`). |\n| `data[].incidents[]` | `array` | Incidents: `id` and `reference`. |\n| `data[].alerts[]` | `array` | Alerts: `id` and `reference`. |\n| `data[].notes[]` | `array` | Notes: `id`, `note`, `reference`. |\n| `data[].dynamicFormSnapshotFields[]` | `array` | Dynamic form answers captured during the booking: `id`, `reference`, `value`, `secondaryValue`, `type`, `snapshotId`. |\n| `metadata.count` | `number` | Total bookings owned by the customer, across all pages. |\n| `metadata.pageNumber` | `number` | Page returned. |\n| `metadata.pageSize` | `number` | Page size applied. |\n| `metadata.totalPages` | `number` | Total number of pages. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `Validation failed (numeric string is expected)` | `customerId` is not an integer. |\n| `400 Bad Request` | — | A pagination parameter has the wrong type or is out of range (for example `pageSize` above `50`). |\n| `401 Unauthorized` | — | Missing or invalid `x-api-key`, or the request does not come from an authorized origin. |\n| `404 Not Found` | `CUSTOMER_NOT_FOUND: {customerId}` | No customer exists with that id. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## The customer must exist\n\n`customerId` must be the id of a Sodtrack customer. Unknown ids, and ids of providers, network users or other account types, are answered with `404 Not Found`. A customer that exists but has no booking is answered with `200 OK` and an empty `data`.\n\n## Bookings are the ones the customer owns\n\n`data` contains every booking whose customer is that user, in any status, including cancelled and completed ones. Bookings where the customer only appears as a requesting party for someone else are not included.\n\n## Provider of a bundled booking\n\nWhen a booking is part of a bundle and has no provider of its own, `provider` shows the provider assigned to the head of the bundle, which is who executes the work.\n\n## Ordering\n\nBookings are ordered by id, newest first.\n\n## Page boundaries\n\nA `pageNumber` beyond the last page is not an error: it returns an empty `data` with the same `metadata.count` and `metadata.totalPages`.",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Get Product Units by Customer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "reference": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "scheduledDate": {
                            "type": "string"
                          },
                          "quantity": {
                            "type": "integer"
                          },
                          "totalDurationMinutes": {
                            "type": "integer"
                          },
                          "doneDate": {
                            "type": "null"
                          },
                          "createdDate": {
                            "type": "string"
                          },
                          "customer": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "reference": {
                                "type": "string"
                              }
                            }
                          },
                          "stakeholder": {
                            "type": "null"
                          },
                          "service": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "variant": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string"
                              },
                              "skus": {
                                "type": "array",
                                "items": {}
                              }
                            }
                          },
                          "category": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "address": {
                            "type": "object",
                            "properties": {
                              "formattedAddress": {
                                "type": "string"
                              },
                              "coordinates": {
                                "type": "null"
                              }
                            }
                          },
                          "originAddress": {
                            "type": "null"
                          },
                          "saleChannel": {
                            "type": "null"
                          },
                          "project": {
                            "type": "null"
                          },
                          "lead": {
                            "type": "null"
                          },
                          "provider": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "reference": {
                                "type": "null"
                              },
                              "name": {
                                "type": "string"
                              },
                              "lastname": {
                                "type": "string"
                              },
                              "email": {
                                "type": "string"
                              },
                              "phone": {
                                "type": "string"
                              },
                              "identificationNumber": {
                                "type": "null"
                              },
                              "assignedTo": {
                                "type": "null"
                              }
                            }
                          },
                          "bookingBundle": {
                            "type": "null"
                          },
                          "price": {
                            "type": "integer"
                          },
                          "cost": {
                            "type": "integer"
                          },
                          "bookingAddOns": {
                            "type": "array",
                            "items": {}
                          },
                          "products": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                },
                                "productType": {
                                  "type": "string"
                                },
                                "quantity": {
                                  "type": "integer"
                                },
                                "serialNumber": {
                                  "type": "string"
                                },
                                "pricing": {
                                  "type": "object",
                                  "properties": {
                                    "price": {
                                      "type": "integer"
                                    },
                                    "cost": {
                                      "type": "integer"
                                    },
                                    "currency": {
                                      "type": "object",
                                      "properties": {
                                        "id": {
                                          "type": "integer"
                                        },
                                        "name": {
                                          "type": "string"
                                        },
                                        "symbol": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "incidents": {
                            "type": "array",
                            "items": {}
                          },
                          "alerts": {
                            "type": "array",
                            "items": {}
                          },
                          "notes": {
                            "type": "array",
                            "items": {}
                          },
                          "dynamicFormSnapshotFields": {
                            "type": "array",
                            "items": {}
                          }
                        }
                      }
                    },
                    "metadata": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "pageNumber": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": 13,
                      "reference": "BK-2026-0456",
                      "status": "accepted",
                      "scheduledDate": "2026-08-26T04:22:29.911Z",
                      "quantity": 1,
                      "totalDurationMinutes": 60,
                      "doneDate": null,
                      "createdDate": "2026-08-26T04:22:29.911Z",
                      "customer": {
                        "id": 32841,
                        "reference": "CUST-00123"
                      },
                      "stakeholder": null,
                      "service": {
                        "id": 1,
                        "name": "Water heater installation"
                      },
                      "variant": {
                        "id": 1,
                        "name": "Standard installation",
                        "type": "execution",
                        "skus": []
                      },
                      "category": {
                        "id": 1,
                        "name": "Installations"
                      },
                      "address": {
                        "formattedAddress": "Av. Corrientes 1234, Buenos Aires",
                        "coordinates": null
                      },
                      "originAddress": null,
                      "saleChannel": null,
                      "project": null,
                      "lead": null,
                      "provider": {
                        "id": 19,
                        "reference": null,
                        "name": "Carlos",
                        "lastname": "Muñoz",
                        "email": "carlos.munoz@example.com",
                        "phone": "+56972345678",
                        "identificationNumber": null,
                        "assignedTo": null
                      },
                      "bookingBundle": null,
                      "price": 0,
                      "cost": 0,
                      "bookingAddOns": [],
                      "products": [
                        {
                          "id": 5,
                          "name": "Water heater 80L",
                          "sku": "WH-80L",
                          "productType": "product",
                          "quantity": 1,
                          "serialNumber": "SN-0001-A",
                          "pricing": {
                            "price": 39999,
                            "cost": 25000,
                            "currency": {
                              "id": 3,
                              "name": "MXN",
                              "symbol": "$"
                            }
                          }
                        }
                      ],
                      "incidents": [],
                      "alerts": [],
                      "notes": [],
                      "dynamicFormSnapshotFields": []
                    },
                    {
                      "id": 12,
                      "reference": "BK-2026-0455",
                      "status": "waiting_customer_to_set_date",
                      "scheduledDate": null,
                      "quantity": 1,
                      "totalDurationMinutes": 60,
                      "doneDate": null,
                      "createdDate": "2026-08-26T04:22:29.911Z",
                      "customer": {
                        "id": 32841,
                        "reference": "CUST-00123"
                      },
                      "stakeholder": null,
                      "service": {
                        "id": 1,
                        "name": "Water heater installation"
                      },
                      "variant": {
                        "id": 1,
                        "name": "Standard installation",
                        "type": "execution",
                        "skus": []
                      },
                      "category": {
                        "id": 1,
                        "name": "Installations"
                      },
                      "address": {
                        "formattedAddress": "Calle Falsa 123, Buenos Aires",
                        "coordinates": null
                      },
                      "originAddress": null,
                      "saleChannel": null,
                      "project": null,
                      "lead": null,
                      "provider": null,
                      "bookingBundle": null,
                      "price": 0,
                      "cost": 0,
                      "bookingAddOns": [],
                      "products": [],
                      "incidents": [],
                      "alerts": [],
                      "notes": [],
                      "dynamicFormSnapshotFields": []
                    }
                  ],
                  "metadata": {
                    "count": 2,
                    "pageNumber": 1,
                    "pageSize": 10,
                    "totalPages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (numeric string is expected) — customerId is not an integer."
          },
          "401": {
            "description": "Missing or invalid x-api-key, or the request does not come from an authorized origin."
          },
          "404": {
            "description": "CUSTOMER_NOT_FOUND: {customerId} — No customer exists with that id."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/incident": {
      "get": {
        "operationId": "incidentsGetEntityIncident",
        "summary": "Get Entity Incident",
        "description": "## General Description\n\nThis endpoint returns the list of incidents associated with a given entity (booking or lead). The entity is identified by query parameters `entity` and `entityId`. Only **booking** and **lead** entities are supported for incident detail; **project** is not supported and returns an error.\n\n* * *\n\n## Query Parameters\n\n| Parameter | Type | Required | Description |\n| --- | --- | --- | --- |\n| `entity` | enum | Yes | Entity type. Must be one of: `booking`, `lead`, `project`. Only `booking` and `lead` are supported for incident detail. |\n| `entityId` | number | Yes | ID of the booking or lead to fetch incidents for. |\n\n* * *\n\n## Success Response\n\nReturns an array of incident objects. Each item includes:\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | number | Incident ID. |\n| `description` | string | Incident description. |\n| `entityType` | string | Entity type (booking or lead). |\n| `entityId` | number | Entity ID. |\n| `bookingIncidentReason` | object | `{ id, name, description }`. |\n| `bookingIncidentStatus` | object | `{ id, name, description }`. |\n| `userReporter` | object | `{ id, name, lastName, email, reference }`. |\n| `userCreator` | object | `{ id, name, lastName, email, reference }`. |\n| `userAccountable` | object | `{ id, name, lastName, email, reference }` (nullable). |\n| `bookingIncidentAttachments` | array | Attachments linked to the incident. |\n| `tasks` | array | Tasks linked to the incident. |\n| `offlineCreatedDate` | string | Offline creation date (when applicable). |\n| `createdDate` | string | Creation date. |\n| `updatedDate` | string | Last update date. |\n| `reference` | string | External reference (optional). |\n| `bookingId` | number | Present when entity is booking. |\n| `bookingVariantName` | string | Present when entity is booking. |\n| `bookingStatus` | string | Present when entity is booking. |\n| `bookingDate` | string | Present when entity is booking. |\n| `bookingReference` | string | Present when entity is booking. |\n| `leadId` | number | Present when entity is lead. |\n| `leadReference` | string | Present when entity is lead (optional). |\n\n* * *\n\n## Example Request\n\n```http\nGET /integration/api/incident?entity=booking&entityId=73\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n```\n\n```json\n[\n  {\n    \"id\": 1,\n    \"description\": \"Customer reported delay\",\n    \"entityType\": \"booking\",\n    \"entityId\": 12345,\n    \"bookingIncidentReason\": { \"id\": 1, \"name\": \"Delay\", \"description\": \"Service delay\" },\n    \"bookingIncidentStatus\": { \"id\": 1, \"name\": \"Open\", \"description\": \"Open\" },\n    \"userReporter\": { \"id\": 10, \"name\": \"John\", \"lastName\": \"Doe\", \"email\": \"john@example.com\", \"reference\": \"USR-001\" },\n    \"userCreator\": { \"id\": 10, \"name\": \"John\", \"lastName\": \"Doe\", \"email\": \"john@example.com\", \"reference\": \"USR-001\" },\n    \"userAccountable\": { \"id\": 11, \"name\": \"Jane\", \"lastName\": \"Smith\", \"email\": \"jane@example.com\", \"reference\": \"USR-002\" },\n    \"bookingIncidentAttachments\": [],\n    \"tasks\": [],\n    \"createdDate\": \"2025-02-20T10:00:00.000Z\",\n    \"updatedDate\": \"2025-02-20T10:00:00.000Z\",\n    \"reference\": \"INC-EXT-001\",\n    \"bookingId\": 12345,\n    \"bookingVariantName\": \"Installation\",\n    \"bookingStatus\": \"scheduled\",\n    \"bookingDate\": \"2025-02-25\",\n    \"bookingReference\": \"BKG-123\"\n  }\n]\n\n```\n\n## Example Error Response\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"ENTITY_NOT_SUPPORTED: Only booking and lead entities are supported for incident detail.\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n* * *",
        "tags": [
          "Incidents"
        ],
        "parameters": [
          {
            "name": "entity",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "booking"
          },
          {
            "name": "entityId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "135"
          }
        ],
        "responses": {
          "200": {
            "description": "Get Entity Incident",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "integer"
                      },
                      "description": {
                        "type": "string"
                      },
                      "bookingId": {
                        "type": "integer"
                      },
                      "bookingVariantName": {
                        "type": "string"
                      },
                      "bookingStatus": {
                        "type": "string"
                      },
                      "bookingDate": {
                        "type": "string"
                      },
                      "bookingReference": {
                        "type": "string"
                      },
                      "bookingIncidentReason": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      },
                      "bookingIncidentStatus": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      },
                      "userReporter": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "lastName": {
                            "type": "string"
                          },
                          "email": {
                            "type": "string"
                          },
                          "reference": {
                            "type": "null"
                          }
                        }
                      },
                      "userCreator": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "lastName": {
                            "type": "string"
                          },
                          "email": {
                            "type": "string"
                          },
                          "reference": {
                            "type": "null"
                          }
                        }
                      },
                      "userAccountable": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "lastName": {
                            "type": "string"
                          },
                          "email": {
                            "type": "string"
                          },
                          "reference": {
                            "type": "null"
                          }
                        }
                      },
                      "bookingIncidentAttachments": {
                        "type": "array",
                        "items": {}
                      },
                      "offlineCreatedDate": {
                        "type": "null"
                      },
                      "createdDate": {
                        "type": "string"
                      },
                      "updatedDate": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": [
                  {
                    "id": 53,
                    "description": "Prueba de inyección de un incidente vía integración. 17-11-2025 incidente 1",
                    "bookingId": 2343,
                    "bookingVariantName": "Presupuesto instalación Electrodomésticos",
                    "bookingStatus": "done",
                    "bookingDate": "2025-11-18T11:00:00.000Z",
                    "bookingReference": "UPDT-2-FROM-EXT-INT",
                    "bookingIncidentReason": {
                      "id": 18,
                      "name": "Incidentes naturales",
                      "description": "Árboles caídos, hoyos en el camino, agua en exceso, nieve, etc"
                    },
                    "bookingIncidentStatus": {
                      "id": 1,
                      "name": "Create",
                      "description": "Created status"
                    },
                    "userReporter": {
                      "id": 15,
                      "name": "Felipe",
                      "lastName": "Hanckes",
                      "email": "felipe@sodtrack.com",
                      "reference": null
                    },
                    "userCreator": {
                      "id": 15,
                      "name": "Felipe",
                      "lastName": "Hanckes",
                      "email": "felipe@sodtrack.com",
                      "reference": null
                    },
                    "userAccountable": {
                      "id": 15,
                      "name": "Felipe",
                      "lastName": "Hanckes",
                      "email": "felipe@sodtrack.com",
                      "reference": null
                    },
                    "bookingIncidentAttachments": [],
                    "offlineCreatedDate": null,
                    "createdDate": "2025-11-17T17:34:46.856Z",
                    "updatedDate": "2025-11-17T17:34:46.856Z",
                    "reference": "ext-int-creation#1"
                  },
                  {
                    "id": 54,
                    "description": "Prueba de inyección de un incidente vía integración. 17-11-2025 incidente 2 update 1",
                    "bookingId": 2343,
                    "bookingVariantName": "Presupuesto instalación Electrodomésticos",
                    "bookingStatus": "done",
                    "bookingDate": "2025-11-18T11:00:00.000Z",
                    "bookingReference": "UPDT-2-FROM-EXT-INT",
                    "bookingIncidentReason": {
                      "id": 18,
                      "name": "Incidentes naturales",
                      "description": "Árboles caídos, hoyos en el camino, agua en exceso, nieve, etc"
                    },
                    "bookingIncidentStatus": {
                      "id": 2,
                      "name": "resuelto",
                      "description": "El incidente fue resuelto"
                    },
                    "userReporter": {
                      "id": 15,
                      "name": "Felipe",
                      "lastName": "Hanckes",
                      "email": "felipe@sodtrack.com",
                      "reference": null
                    },
                    "userCreator": {
                      "id": 15,
                      "name": "Felipe",
                      "lastName": "Hanckes",
                      "email": "felipe@sodtrack.com",
                      "reference": null
                    },
                    "userAccountable": {
                      "id": 16,
                      "name": "Felipe",
                      "lastName": "Hanckes",
                      "email": "felipe+2@sodtrack.com",
                      "reference": null
                    },
                    "bookingIncidentAttachments": [],
                    "offlineCreatedDate": null,
                    "createdDate": "2025-11-17T17:38:59.290Z",
                    "updatedDate": "2025-11-20T03:55:46.668Z",
                    "reference": "ext-int-creation#2"
                  }
                ]
              }
            }
          }
        }
      },
      "post": {
        "operationId": "incidentsCreateIncident",
        "summary": "Create Incident",
        "description": "### **Purpose**\n\nCreates a new incident in Sodtrack and associates it with a **booking**, a **lead**, or a **work order**.\n\nThe target entity is identified by **entityType** (`booking`, `lead`, or `work_order`) and by **entity** (using `entityId` or `entityReference`). The incident requires a **description** and an **incident reason** (by ID; reference is not yet supported). You can optionally set the reporter, creator, and accountable users, an external **reference**, and **dynamic forms** data.\n\nIncidents are used to track issues, complaints, or follow-ups. Only **booking**, **lead** and **work\\_order** are supported for creation.\n\n* * *\n\n### **Field Definitions**\n\n#### 📋 Request body\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `entityType` | `string` | ✅ | Entity type the incident is associated with: `\"booking\"`, `\"lead\"` or `\"work_order\"`. |\n| `entity` | `object` | ✅ | Entity identifier: how to find the booking, lead, or work order (by ID or reference). |\n| `description` | `string` | ✅ | Description of the incident. |\n| `incidentReason` | `object` | ✅ | Incident reason identifier. Only `reasonId` is supported; `reasonReference` is not yet supported. |\n| `reporterUser` | `object` | ❌ | User who reported the incident. If provided and not resolved, the request fails. |\n| `creatorUser` | `object` | ❌ | User who created the incident. If provided and not resolved, the request fails. |\n| `accountableUser` | `object` | ❌ | User accountable for resolving the incident. Optional. |\n| `reference` | `string` | ❌ | External reference for the incident. |\n| `dynamicForms` | `array[object]` | ❌ | Optional form data (if configured for incident creation). See **Dynamic forms** below. |\n\n* * *\n\n#### 📝 Dynamic forms\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `dynamicForms` | `array[object]` | ❌ | List of form snapshots to submit. |\n| `dynamicForms[].formReference` | `string` | ✅ when form sent | Identifier of the form (must match a form configured for the incident creation flow). |\n| `dynamicForms[].values` | `array[object]` | ✅ when form sent | List of field values for this form. |\n| `dynamicForms[].values[].fieldReference` | `string` | ✅ | Identifier of the form field (must match a field in the form). |\n| `dynamicForms[].values[].value` | `string` | ✅ | Submitted value for the field. Numbers are accepted and converted to string. |\n\n#### 🔗 Entity identifier\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `entity.type` | `string` | ✅ | How the entity is identified: `\"entityId\"` or `\"entityReference\"`. |\n| `entity.value` | `string` | ✅ | The entity ID (if type is `entityId`) or the entity reference (if type is `entityReference`) for the selected `entityType` (booking, lead, or work order). Must be non-empty. |\n\n* * *\n\n#### 📌 Incident reason identifier\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `incidentReason.type` | `string` | ✅ | Must be `\"reasonId\"`. `\"reasonReference\"` is not yet supported. |\n| `incidentReason.value` | `string` | ✅ | Numeric ID of the incident reason (must exist in Sodtrack). |\n\n* * *\n\n#### 👤 User information (reporter, creator, accountable)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | `string` | ✅ when user object sent | User identifier type: `\"userId\"`, `\"userEmail\"`, or `\"userReference\"`. |\n| `value` | `string` | ✅ when user object sent | The user ID, email, or reference according to `type`. |\n\n### **Example Request (booking by reference)**\n\n```json\n{\n  \"entityType\": \"booking\",\n  \"entity\": {\n    \"type\": \"entityReference\",\n    \"value\": \"BOOK-REF-001\"\n  },\n  \"description\": \"Técnico no llevó el equipo correcto.\",\n  \"incidentReason\": {\n    \"type\": \"reasonId\",\n    \"value\": \"2\"\n  },\n  \"reporterUser\": {\n    \"type\": \"userEmail\",\n    \"value\": \"soporte@example.com\"\n  },\n  \"creatorUser\": {\n    \"type\": \"userReference\",\n    \"value\": \"USER-EXT-001\"\n  },\n  \"reference\": \"INC-EXT-2025-001\"\n}\n\n```\n\n### **Example Request (lead by reference)**\n\n```json\n{\n  \"entityType\": \"lead\",\n  \"entity\": {\n    \"type\": \"entityReference\",\n    \"value\": \"LEAD-EXT-342\"\n  },\n  \"description\": \"Queja por demora en agendamiento.\",\n  \"incidentReason\": {\n    \"type\": \"reasonId\",\n    \"value\": \"2\"\n  },\n  \"reporterUser\": {\n    \"type\": \"userEmail\",\n    \"value\": \"soporte@example.com\"\n  },\n  \"creatorUser\": {\n    \"type\": \"userEmail\",\n    \"value\": \"soporte@example.com\"\n  },\n  \"reference\": \"INC-LEAD-001\",\n  \"dynamicForms\": [\n    {\n      \"formReference\": \"incident_creation_form\",\n      \"values\": [\n        {\n          \"fieldReference\": \"incident_creation_form_field_1\",\n          \"value\": \"Yes\"\n        }\n      ]\n    }\n  ]\n}\n\n```\n\n### **Example Request (work order by reference)**\n\n```json\n{\n  \"entityType\": \"work_order\",\n  \"entity\": {\n    \"type\": \"entityReference\",\n    \"value\": \"WO-EXT-778\"\n  },\n  \"description\": \"Repuesto incorrecto enviado en la orden de trabajo.\",\n  \"incidentReason\": {\n    \"type\": \"reasonId\",\n    \"value\": \"3\"\n  },\n  \"reporterUser\": {\n    \"type\": \"userEmail\",\n    \"value\": \"soporte@example.com\"\n  },\n  \"reference\": \"INC-WO-001\"\n}\n\n```\n\n### **Example Request (minimal)**\n\n```json\n{\n  \"entityType\": \"booking\",\n  \"entity\": {\n    \"type\": \"entityId\",\n    \"value\": \"12345\"\n  },\n  \"description\": \"Incidente reportado por integración.\",\n  \"incidentReason\": {\n    \"type\": \"reasonId\",\n    \"value\": \"1\"\n  }\n}\n\n```\n\n* * *\n\n### **Response Example**\n\n```json\n{\n  \"id\": 100,\n  \"entityType\": \"booking\",\n  \"entityId\": 12345,\n  \"bookingId\": 12345,\n  \"incidentStatus\": {\n    \"id\": 1,\n    \"name\": \"Open\",\n    \"description\": \"Incident is open\",\n    \"isFinalStatus\": false,\n    \"isInitialStatus\": true,\n    \"bookingStatusUpdate\": \"\"\n  },\n  \"reference\": \"INC-EXT-001\"\n}\n\n```\n\nWhen `entityType` is `\"work_order\"`, the response carries the work order id in `entityId` and omits `bookingId`:\n\n```json\n{\n  \"id\": 101,\n  \"entityType\": \"work_order\",\n  \"entityId\": 778,\n  \"incidentStatus\": {\n    \"id\": 1,\n    \"name\": \"Open\",\n    \"description\": \"Incident is open\",\n    \"isFinalStatus\": false,\n    \"isInitialStatus\": true,\n    \"bookingStatusUpdate\": \"\"\n  },\n  \"reference\": \"INC-WO-001\"\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack incident ID. |\n| `entityType` | `string` | Entity type: `\"booking\"`, `\"lead\"`, or `\"work_order\"`. |\n| `entityId` | `number` | Entity ID (booking id, lead id, or work order id). |\n| `bookingId` | `number` | Present only when `entityType` is `\"booking\"`. |\n| `incidentStatus` | `object` | Initial incident status (id, name, description, isFinalStatus, isInitialStatus, bookingStatusUpdate). |\n| `reference` | `string` | External reference if provided in the request. |\n\n* * *\n\n### \\*_Error Responses_ \\*\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `ENTITY_IDENTIFIER_REQUIRED` | `entity.value` is missing or empty. |\n| `400 Bad Request` | `ENTITY_TYPE_NOT_SUPPORTED` | `entityType` is not supported for creation. Only `booking`, `lead`, and `work_order` are supported. |\n| `400 Bad Request` | `BOOKING_NOT_FOUND_FOR_ID` | No booking found for the given entity ID. |\n| `400 Bad Request` | `BOOKING_NOT_FOUND_FOR_REFERENCE` | No booking found for the given entity reference. |\n| `400 Bad Request` | `MULTIPLE_BOOKINGS_FOUND_FOR_REFERENCE` | More than one booking shares the given reference. |\n| `400 Bad Request` | `LEAD_NOT_FOUND_FOR_ID` | No lead found for the given entity ID. |\n| `400 Bad Request` | `LEAD_NOT_FOUND_FOR_REFERENCE` | No lead found for the given entity reference. |\n| `400 Bad Request` | `INVALID_WORK_ORDER_ID` | `entity.value` is not a number when resolving a work order by ID. |\n| `400 Bad Request` | `WORK_ORDER_NOT_FOUND_FOR_ID` | No work order found for the given entity ID. |\n| `400 Bad Request` | `WORK_ORDER_NOT_FOUND_FOR_REFERENCE` | No work order found for the given entity reference. |\n| `400 Bad Request` | `INVALID_REPORTER_USER` | `reporterUser` was provided but could not be resolved. |\n| `400 Bad Request` | `INVALID_CREATOR_USER` | `creatorUser` was provided but could not be resolved. |\n| `400 Bad Request` | `INVALID_USER_TYPE` | Invalid user identifier type. |\n| `400 Bad Request` | `INVALID_INCIDENT_REASON_ID` | Reason id must be a number. |\n| `400 Bad Request` | `INCIDENT_REASON_NOT_FOUND` | The incident reason ID does not exist in Sodtrack. |\n| `400 Bad Request` | `INCIDENT_REASON_REFERENCE_NOT_SUPPORTED` | Resolution by `reasonReference` is not yet supported. Use `reasonId`. |\n| `400 Bad Request` | `INVALID_INCIDENT_REASON_TYPE` | Invalid incident reason identifier type. |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid. |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Entity identification\n\n-   **entityType** and **entity** are required. Supported values for creation are **`booking`**, **`lead`**, and **`work_order`**. The enum may also include `project`; it is **not supported** for this endpoint and returns `ENTITY_TYPE_NOT_SUPPORTED`.\n-   **entity.value** must be non-empty (after trim). Otherwise the request fails with `ENTITY_IDENTIFIER_REQUIRED`.\n\n* * *\n\n## Booking resolution\n\nWhen **entityType** is `booking`:\n\n-   **entity.type = entityId:** `value` is the booking ID. The booking must exist; otherwise the API returns `BOOKING_NOT_FOUND_FOR_ID`.\n-   **entity.type = entityReference:** `value` is the booking reference. No match returns `BOOKING_NOT_FOUND_FOR_REFERENCE`; multiple matches return `MULTIPLE_BOOKINGS_FOUND_FOR_REFERENCE`.\n\n* * *\n\n## Lead resolution\n\nWhen **entityType** is `lead`:\n\n-   **entity.type = entityId:** `value` is the lead ID. The lead must exist; otherwise the API returns `LEAD_NOT_FOUND_FOR_ID`.\n-   **entity.type = entityReference:** `value` is the lead reference. The lead must exist; otherwise the API returns `LEAD_NOT_FOUND_FOR_REFERENCE`.\n\n* * *\n\n## Work order resolution\n\nWhen **entityType** is `work_order`:\n\n-   **entity.type = entityId:** `value` is the work order ID and must be numeric; a non-numeric value returns `INVALID_WORK_ORDER_ID`. The work order must exist; otherwise the API returns `WORK_ORDER_NOT_FOUND_FOR_ID`.\n-   **entity.type = entityReference:** `value` is the work order external reference. No match returns `WORK_ORDER_NOT_FOUND_FOR_REFERENCE`.\n\n* * *\n\n## User resolution\n\n-   **reporterUser** and **creatorUser** are optional and can be sent as `null`. When either is provided with a non-null value, it must resolve to an existing user by the given identifier (`userId`, `userEmail`, or `userReference`). If the user cannot be resolved, the request fails with `INVALID_REPORTER_USER` or `INVALID_CREATOR_USER` respectively.\n-   **accountableUser** is optional. When provided, it is resolved if possible; if it cannot be resolved, the incident may be created without an accountable user (behavior may depend on configuration).\n-   Invalid user identifier **type** returns `INVALID_USER_TYPE`.\n\n* * *\n\n## Incident reason\n\n-   **incidentReason** is required. Only **type = reasonId** is supported; **reasonReference** is not yet supported and returns `INCIDENT_REASON_REFERENCE_NOT_SUPPORTED`.\n-   **value** must be a valid numeric reason ID that exists in Sodtrack. Invalid number returns `INVALID_INCIDENT_REASON_ID`; non-existent reason returns `INCIDENT_REASON_NOT_FOUND`.\n\n* * *\n\n## Data and format\n\n-   Dynamic form data (when provided) is validated and stored for the incident according to the incident creation flow configuration.\n-   All timestamps in responses follow ISO 8601 format (UTC) where applicable.",
        "tags": [
          "Incidents"
        ],
        "parameters": [],
        "responses": {
          "201": {
            "description": "Create Incident",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "entityType": {
                      "type": "string"
                    },
                    "entityId": {
                      "type": "integer"
                    },
                    "incidentStatus": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "name": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        },
                        "isFinalStatus": {
                          "type": "boolean"
                        },
                        "isInitialStatus": {
                          "type": "boolean"
                        },
                        "bookingStatusUpdate": {
                          "type": "string"
                        }
                      }
                    },
                    "reference": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": 71,
                  "entityType": "lead",
                  "entityId": 278,
                  "incidentStatus": {
                    "id": 1,
                    "name": "Create",
                    "description": "Created status",
                    "isFinalStatus": false,
                    "isInitialStatus": true,
                    "bookingStatusUpdate": ""
                  },
                  "reference": "INC-EXT-2026-001"
                }
              }
            }
          },
          "400": {
            "description": "ENTITY_IDENTIFIER_REQUIRED — entity.value is missing or empty."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      },
      "patch": {
        "operationId": "incidentsUpdateIncident",
        "summary": "Update Incident",
        "description": "### **Purpose**\n\nUpdates an existing incident in Sodtrack.\n\nThe incident is identified by **incident** (by `incidentId` or `incidentReference`). Only the fields you send are updated; omitted fields keep their current values. You can update the **description**, **incident status**, **accountable user**, and **dynamic forms** data.\n\n* * *\n\n### **Field Definitions**\n\n#### 📋 Request body\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `incident` | `object` | ✅ | Incident identifier (by ID or reference). |\n| `description` | `string` | ❌ | New incident description. Only sent if you want to change it. |\n| `incidentStatus` | `object` | ❌ | New incident status identifier. Only **statusId** is supported; **statusReference** is not yet supported. |\n| `accountableUser` | `object` | ❌ | New user accountable for the incident. If provided, must resolve to an existing user. |\n| `dynamicForms` | `array[object]` | ❌ | Optional form data (if configured for incident status change). See **Dynamic forms** below. |\n\n* * *\n\n#### 📝 Dynamic forms\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `dynamicForms` | `array[object]` | ❌ | List of form snapshots to submit. |\n| `dynamicForms[].formReference` | `string` | ✅ when form sent | Identifier of the form (must match a form configured for the incident status change flow). |\n| `dynamicForms[].values` | `array[object]` | ✅ when form sent | List of field values for this form. |\n| `dynamicForms[].values[].fieldReference` | `string` | ✅ | Identifier of the form field (must match a field in the form). |\n| `dynamicForms[].values[].value` | `string` | ✅ | Submitted value for the field. Numbers are accepted and converted to string. |\n\n#### 📌 Incident status identifier\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `incidentStatus.type` | `string` | ✅ when incidentStatus sent | Must be `\"statusId\"`. `\"statusReference\"` is not yet supported. |\n| `incidentStatus.value` | `string` | ✅ when incidentStatus sent | Numeric ID of the incident status (must exist in Sodtrack). |\n\n* * *\n\n#### 👤 User information (accountable)\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | `string` | ✅ when accountableUser sent | User identifier type: `\"userId\"`, `\"userEmail\"`, or `\"userReference\"`. |\n| `value` | `string` | ✅ when accountableUser sent | The user ID, email, or reference according to `type`. |\n\n* * *\n\n### **Example Request (by incident reference)**\n\n```json\n{\n  \"incident\": {\n    \"type\": \"incidentReference\",\n    \"value\": \"INC-EXT-2025-001\"\n  },\n  \"description\": \"Actualizado: resolución en progreso.\",\n  \"incidentStatus\": {\n    \"type\": \"statusId\",\n    \"value\": \"2\"\n  },\n  \"accountableUser\": {\n    \"type\": \"userEmail\",\n    \"value\": \"manager@example.com\"\n  }\n}\n\n```\n\n### **Example Request (by incident ID)**\n\n```json\n{\n  \"incident\": {\n    \"type\": \"incidentId\",\n    \"value\": \"101\"\n  },\n  \"description\": \"Descripción actualizada del incidente.\",\n  \"incidentStatus\": {\n    \"type\": \"statusId\",\n    \"value\": \"3\"\n  },\n  \"dynamicForms\": [\n        {\n            \"formReference\": \"incident_status_update_form\",\n            \"values\": [\n                {\n                    \"fieldReference\": \"incident_status_update_form_field_1\",\n                    \"value\": \"yesterday\"\n                }\n            ]\n        }\n    ]\n}\n\n```\n\n### **Example Request (minimal — change status only)**\n\n```json\n{\n  \"incident\": {\n    \"type\": \"incidentId\",\n    \"value\": \"101\"\n  },\n  \"incidentStatus\": {\n    \"type\": \"statusId\",\n    \"value\": \"2\"\n  }\n}\n\n```\n\n* * *\n\n### **Response Example**\n\n```json\n{\n  \"id\": 101,\n  \"entityType\": \"booking\",\n  \"entityId\": 12345,\n  \"bookingId\": 12345,\n  \"incidentStatus\": {\n    \"id\": 2,\n    \"name\": \"In Progress\",\n    \"description\": \"In Progress\",\n    \"isFinalStatus\": false,\n    \"isInitialStatus\": false,\n    \"bookingStatusUpdate\": \"\"\n  }\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Incident ID. |\n| `entityType` | `string` | Entity type: `\"booking\"` or `\"lead\"`. |\n| `entityId` | `number` | Entity ID (booking id or lead id). |\n| `bookingId` | `number` | Present only when `entityType` is `\"booking\"`. |\n| `incidentStatus` | `object` | Updated incident status (id, name, description, isFinalStatus, isInitialStatus, bookingStatusUpdate). |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `INCIDENT_NOT_FOUND` | No incident found for the given ID or reference. |\n| `400 Bad Request` | `MULTIPLE_INCIDENTS_FOUND_FOR_REFERENCE` | More than one incident matches the given reference. |\n| `400 Bad Request` | `INVALID_INCIDENT_TYPE` | Invalid incident identifier type (must be `incidentId` or `incidentReference`). |\n| `400 Bad Request` | `INVALID_ACCOUNTABLE_USER` | `accountableUser` was provided but could not be resolved to an existing user. |\n| `400 Bad Request` | `INVALID_INCIDENT_STATUS_ID` | Status id must be a number. |\n| `400 Bad Request` | `INCIDENT_STATUS_NOT_FOUND` | The incident status ID does not exist in Sodtrack. |\n| `400 Bad Request` | `INCIDENT_STATUS_REFERENCE_NOT_SUPPORTED` | Resolution by `statusReference` is not yet supported. Use `statusId`. |\n| `400 Bad Request` | `INVALID_INCIDENT_STATUS_TYPE` | Invalid incident status identifier type. |\n| `400 Bad Request` | `InvalidParameters` | One or more required fields are missing or invalid. |\n| `401 Unauthorized` | — | Authentication token missing or expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Incident identification\n\n-   **incident** is required, with **type** and **value**.\n    \n-   **type** must be `incidentId` or `incidentReference`. Any other value returns `INVALID_INCIDENT_TYPE`.\n    \n-   If no incident is found for the given ID or reference, the API returns `INCIDENT_NOT_FOUND`.\n    \n-   When **type = incidentReference**, if more than one incident matches the reference, the API returns `MULTIPLE_INCIDENTS_FOUND_FOR_REFERENCE`.\n    \n\n* * *\n\n## Update behavior\n\n-   **description**, **incidentStatus**, and **accountableUser** are optional. Only provided fields are updated; omitted fields leave existing values unchanged.\n    \n-   You can send only **incident** plus one or more of description, status, and accountable user.\n    \n\n* * *\n\n## Accountable user\n\n-   When **accountableUser** is provided, it must resolve to an existing user (by `userId`, `userEmail`, or `userReference`). If the user cannot be resolved, the request fails with `INVALID_ACCOUNTABLE_USER`.\n\n* * *\n\n## Incident status\n\n-   **incidentStatus** (when provided) must use **type = statusId**. **statusReference** is not yet supported and returns `INCIDENT_STATUS_REFERENCE_NOT_SUPPORTED`.\n    \n-   **value** must be a valid numeric status ID that exists in Sodtrack. Invalid number returns `INVALID_INCIDENT_STATUS_ID`; non-existent status returns `INCIDENT_STATUS_NOT_FOUND`.\n    \n\n* * *\n\n## Data and format\n\n-   Dynamic form data (when provided) is validated and stored according to the incident status change flow configuration.\n    \n-   All timestamps in responses follow ISO 8601 format (UTC) where applicable.",
        "tags": [
          "Incidents"
        ],
        "parameters": [],
        "responses": {
          "201": {
            "description": "Create Incident",
            "content": {
              "text/plain": {
                "example": {
                  "id": 45,
                  "bookingId": 1515,
                  "incidentStatus": {
                    "id": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "INCIDENT_NOT_FOUND — No incident found for the given ID or reference."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/area-pricing": {
      "patch": {
        "operationId": "areaPricingUpdateComponentPriceCost",
        "summary": "Update Component Price/Cost",
        "description": "### **Purpose**\n\nCreates or updates the **area-based pricing** (price and cost per geographic area) of a **component** product in Sodtrack.\n\nThis endpoint works as an **upsert**: it locates (or creates) the pricing record of the referenced component and then applies each pricing group you send. Each group assigns a `price` and `cost` to a set of areas.\n\nAn area can only belong to one pricing group at a time. If an area you send is currently assigned to another group, Sodtrack **moves** it to the new group automatically (it is removed from its previous group; if that group is left empty it is deleted).\n\nThe whole request is validated **before** any change is applied, so a request that fails a business rule is rejected without leaving partial changes.\n\n* * *\n\n### **Field Definitions**\n\n#### 🔐 **Authentication**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `x-api-key` (header) | `string` | ✅ | Sodtrack integration API key. Requests with a missing/invalid key (or from an unauthorized network) are rejected. |\n\n#### 🧩 **Component**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `product` | `object` | ✅ | The component whose pricing is being set. Must reference a product of type **component**. |\n| `product.type` | `string` | ✅ | How the component is identified. One of: `\"productSku\"`, `\"productId\"`. |\n| `product.value` | `string` | ✅ | The component SKU (when `type` is `\"productSku\"`) or the numeric component id (when `type` is `\"productId\"`). |\n\n#### 💲 **Area pricing groups**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `areas` | `array` | ✅ | Non-empty list of pricing groups. Each group sets a `price`/`cost` for one set of areas. |\n| `areas[].type` | `string` | ✅ | How the areas in this group are identified. One of: `\"areaId\"`, `\"areaReference\"`. |\n| `areas[].values` | `string[]` | ✅ | Non-empty list of area identifiers: area ids (when `type` is `\"areaId\"`) or area reference codes (when `type` is `\"areaReference\"`). |\n| `areas[].price` | `number` | ✅ | Sale price applied to those areas. |\n| `areas[].cost` | `number` | ✅ | Cost applied to those areas. |\n\n> All areas within a single group must share the same currency. An area cannot appear in more than one group in the same request.\n\n* * *\n\n### **Example Request**\n\n```json\n{\n  \"product\": {\n    \"type\": \"productSku\",\n    \"value\": \"MOTO-REPUESTO-AREA-0001\"\n  },\n  \"areas\": [\n    { \"type\": \"areaId\", \"values\": [\"1\"], \"price\": 100, \"cost\": 80 },\n    { \"type\": \"areaReference\", \"values\": [\"HN\", \"CR\"], \"price\": 5000, \"cost\": 4000 }\n  ]\n}\n```\n\n### **Response Example**\n\n```json\n{\n  \"id\": 45,\n  \"entityType\": \"COMPONENT\",\n  \"entityRefId\": \"163\",\n  \"active\": true,\n  \"itemsCount\": 2,\n  \"items\": [\n    {\n      \"id\": 101,\n      \"price\": 100,\n      \"cost\": 80,\n      \"areas\": [{ \"id\": 1, \"name\": \"Nicaragua\", \"code\": \"NIC\" }]\n    },\n    {\n      \"id\": 102,\n      \"price\": 5000,\n      \"cost\": 4000,\n      \"areas\": [\n        { \"id\": 7, \"name\": \"Honduras\", \"code\": \"HN\" },\n        { \"id\": 8, \"name\": \"Costa Rica\", \"code\": \"CR\" }\n      ]\n    }\n  ],\n  \"component\": {\n    \"id\": 163,\n    \"sku\": \"MOTO-REPUESTO-AREA-0001\",\n    \"name\": \"Kit de servicio motocicleta\"\n  },\n  \"createdDate\": \"2026-06-05T05:10:23.362Z\"\n}\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier of the pricing record. |\n| `entityType` | `string` | Always `\"COMPONENT\"` for this endpoint. |\n| `entityRefId` | `string` | The component id this pricing belongs to. |\n| `active` | `boolean` | Whether the pricing record is active. |\n| `itemsCount` | `number` | Number of pricing groups currently configured. |\n| `items[].id` | `number` | Identifier of the pricing group. |\n| `items[].price` | `number` | Price configured for the group's areas. |\n| `items[].cost` | `number` | Cost configured for the group's areas. |\n| `items[].areas[]` | `array` | Resolved areas in the group (each includes its `id`, `name`, and reference `code`). |\n| `component` | `object` | The component the pricing belongs to (`id`, `sku`, `name`). |\n| `createdDate` | `string` | ISO date when the pricing record was created. |\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error | Description |\n| --- | --- | --- |\n| `400 Bad Request` | — | The referenced product is not a component, the component lookup `type` is not supported, an area id is not numeric, an area reference is ambiguous, an area appears in more than one group, or a group mixes areas of different currencies. |\n| `401 Unauthorized` | — | API key missing/invalid, or request not from an authorized network. |\n| `404 Not Found` | — | The component (by id/SKU) or a referenced area (by id/reference) was not found. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Upsert behavior\n\nIf the component has no pricing record yet, Sodtrack creates one. Each group in `areas` is then applied:\n\n| Scenario | Behavior |\n| --- | --- |\n| Group's exact area set already exists | Its `price`/`cost` is updated (skipped if unchanged). |\n| Group's area set is new | A new pricing group is created. |\n| An area is already in another group | The area is moved to the new group; its previous group keeps its remaining areas (or is removed if left empty). |\n\n## All-or-nothing validation\n\nThe request is fully validated before any write: components and areas must resolve, no area can be repeated across groups, and each group's areas must share one currency. If any check fails, the request is rejected and nothing is changed.\n\n## Area identification\n\n-   `areaId`: each value must be a numeric, active area id.\n-   `areaReference`: each value must match exactly one active area by its reference code (an ambiguous code is rejected).\n\n* * *",
        "tags": [
          "Area Pricing"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Update product area",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "entityType": {
                      "type": "string"
                    },
                    "entityRefId": {
                      "type": "string"
                    },
                    "active": {
                      "type": "boolean"
                    },
                    "itemsCount": {
                      "type": "integer"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "price": {
                            "type": "integer"
                          },
                          "cost": {
                            "type": "integer"
                          },
                          "areas": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "integer"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "code": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "component": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "sku": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      }
                    },
                    "createdDate": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": 45,
                  "entityType": "COMPONENT",
                  "entityRefId": "163",
                  "active": true,
                  "itemsCount": 2,
                  "items": [
                    {
                      "id": 101,
                      "price": 100,
                      "cost": 80,
                      "areas": [
                        {
                          "id": 1,
                          "name": "Nicaragua",
                          "code": "NIC"
                        }
                      ]
                    },
                    {
                      "id": 102,
                      "price": 5000,
                      "cost": 4000,
                      "areas": [
                        {
                          "id": 7,
                          "name": "Honduras",
                          "code": "HN"
                        },
                        {
                          "id": 8,
                          "name": "Costa Rica",
                          "code": "CR"
                        }
                      ]
                    }
                  ],
                  "component": {
                    "id": 163,
                    "sku": "MOTO-REPUESTO-AREA-0001",
                    "name": "Kit de servicio motocicleta"
                  },
                  "createdDate": "2026-06-05T05:10:23.362Z"
                }
              }
            }
          },
          "400": {
            "description": "The referenced product is not a component, the component lookup type is not supported, an area id is not numeric, an area reference is ambiguous, an area appears in more than one group, or a group mixes areas of different currencies."
          },
          "401": {
            "description": "API key missing/invalid, or request not from an authorized network."
          },
          "404": {
            "description": "The component (by id/SKU) or a referenced area (by id/reference) was not found."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/attachment/find-by-ids": {
      "post": {
        "operationId": "attachmentFindAttachmentsByIds",
        "summary": "Find attachments by ids",
        "description": "### Field Definitions\n\n#### Top-level\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| customer | object | ✅ | Basic customer information. |\n| serviceId | number | ✅ | ID of the service associated with the lead. |\n| salesChannelId | number | ✅ | ID of the originating sales channel. |\n| qualifyingQuestions | array | ✅ | Answers to the lead’s qualifying questions. |\n| addressData | object | ✅ | Customer address data; required if the service variant must be performed at the customer location. |\n| dynamicForm | array | ❌ | Forms (and values) to associate with the lead creation. |\n| reference | string | ❌ | Optional reference identifier |\n\n#### customer\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| customer.name | string | ✅ | Customer first name. |\n| customer.lastName | string | ✅ | Customer last name. |\n| customer.phoneNumber | string | ✅ | Client phone number including “+” and country code. |\n| customer.email | string | ✅ | Customer email. |\n| customer.identificationNumber | string | ✅ | Customer fiscal/tax ID. |\n| customer.identificationNumberCountry | string | ✅ | Country code in ISO‑2 format (e.g., US, CL). |\n| customer.reference | string | ❌ | Optional reference identifier |\n\n#### qualifyingQuestions\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| qualifyingQuestions\\[\\].fieldReference | number | ✅ | ID of the question to be answered. |\n| qualifyingQuestions\\[\\].value | string | ✅ | Answer to the question. |\n\n#### addressData\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| addressData.extra\\_info | string | ❌ | Additional info to locate the address (e.g., “apt 34”, “office 83”). |\n| addressData.address | string | ✅ | Written customer address. |\n| addressData.coordinate | object | ✅ | Geolocation of the customer address. |\n| addressData.coordinate.lat | number | ✅ | Latitude. |\n| addressData.coordinate.lng | number | ✅ | Longitude. |\n\n#### dynamicForm\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| dynamicForm\\[\\].externalReference | string | ✅ | Reference of the form to be completed. |\n| dynamicForm\\[\\].values | array | ✅ | Array of responses for that form. |\n| dynamicForm\\[\\].values\\[\\].FieldReference | string | ✅ | Dynamic Form field reference |\n| dynamicForm\\[\\].values\\[\\].value | string | ✅ | Field value. |",
        "tags": [
          "Attachment"
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "dev.api.cl.sodtrack.sodtrack.com"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "attachmentIds": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  }
                }
              },
              "example": {
                "attachmentIds": [
                  21
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Create Lead",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "customer_id": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "id": 4,
                  "customer_id": 15
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/alert": {
      "post": {
        "operationId": "alertsCreateAnAlert",
        "summary": "Create an Alert",
        "description": "## General Description\n\nCreates a new alert for an entity resolved by polymorphic identifier (`entityId` or `entityReference`) plus `entityType`.\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationCreateAlertRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `entityType` | enum | Yes | Entity type where alert is created can be one of `booking`, `lead`, `project` or `budget` |\n| `entity` | `ExternalIntegrationEntityIdentifierRequestDTO` | Yes | Entity identifier object. |\n| `name` | string | Yes | Alert name. |\n| `resolveType` | enum | No | Resolve behavior. Supported in this flow: `manual`, `sticky`. |\n| `metricKey` | string | No | Optional metric key. |\n| `metricValue` | string | No | Optional metric value. |\n| `createdComment` | string | No | Optional creation comment. |\n| `reference` | string | No | Optional external alert reference (must be unique). |\n\n### `ExternalIntegrationEntityIdentifierRequestDTO`\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | Identifier type: `entityId` or `entityReference`. |\n| `value` | string | Yes | Entity ID value (when `entityId`) or reference value (when `entityReference`). |\n\n## Success Response\n\nReturns `AlertDTO`.\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | number | Alert ID. |\n| `uuid` | string | Alert UUID. |\n| `entityType` | enum | Alert entity type. |\n| `entityId` | number | Resolved entity ID. |\n| `name` | string | Alert name. |\n| `status` | enum | `active` or `resolved`. |\n| `creationUserType` | enum | `integration_api` for this flow. |\n| `createdByUserId` | number | null |\n| `creationType` | enum | Creation mode. |\n| `resolveType` | enum | Resolve type of alert. |\n| `metricKey` | string | null |\n| `metricValue` | string | null |\n| `createdComment` | string | null |\n| `reference` | string | null |\n| `resolvedComment` | string | null |\n| `resolvedByUserId` | number | null |\n| `resolvedDate` | Date | null |\n| `createdDate` | Date | Created timestamp. |\n| `updatedDate` | Date | Updated timestamp. |\n\n* * *\n\n## Example Request\n\n```json\n{\n  \"entityType\": \"booking\",\n  \"entity\": {\n    \"type\": \"entityReference\",\n    \"value\": \"BKG-EXT-100\"\n  },\n  \"name\": \"Technician unavailable\",\n  \"resolveType\": \"manual\",\n  \"metricKey\": \"capacity\",\n  \"metricValue\": \"0\",\n  \"createdComment\": \"Created from external monitoring\",\n  \"reference\": \"EXT-ALERT-100\"\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 201 Created\n\n```\n\n```json\n{\n  \"id\": 10,\n  \"uuid\": \"d73c51c5-3fbe-4d8e-8f24-2ecce2f8e8e1\",\n  \"entityType\": \"booking\",\n  \"entityId\": 12345,\n  \"name\": \"Technician unavailable\",\n  \"status\": \"active\",\n  \"creationUserType\": \"integration_api\",\n  \"createdByUserId\": null,\n  \"creationType\": \"manual\",\n  \"resolveType\": \"manual\",\n  \"metricKey\": \"capacity\",\n  \"metricValue\": \"0\",\n  \"createdComment\": \"Created from external monitoring\",\n  \"reference\": \"EXT-ALERT-100\",\n  \"resolvedComment\": null,\n  \"resolvedByUserId\": null,\n  \"resolvedDate\": null,\n  \"createdDate\": \"2026-02-24T10:00:00.000Z\",\n  \"updatedDate\": \"2026-02-24T10:00:00.000Z\"\n}\n\n```\n\n## Example Error Responses\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"INVALID_ENTITY_IDENTIFIER_TYPE\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"BUDGET_REFERENCE_NOT_SUPPORTED\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 409,\n  \"message\": \"ALERT_REFERENCE_ALREADY_EXISTS\",\n  \"error\": \"Conflict\"\n}\n\n```\n\n# Business Rules & Constraints\n\n-   `entity.type` must be exactly `entityId` or `entityReference`; otherwise returns `INVALID_ENTITY_IDENTIFIER_TYPE`.\n    \n-   Entity resolution requires exactly one identifier value that maps to exactly one instance of the entity.\n    \n    -   If entity cannot be resolved: `ENTITY_NOT_FOUND`.\n        \n    -   If reference maps to multiple entities: `MULTIPLE_ENTITIES_FOUND`.\n        \n-   For `entityType = budget`, reference-based resolution is not supported yet `BUDGET_REFERENCE_NOT_SUPPORTED`.\n    \n-   `reference`, when provided, must be unique; duplicate returns `ALERT_REFERENCE_ALREADY_EXISTS`.",
        "tags": [
          "Alerts"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "entityType": {
                    "type": "string"
                  },
                  "entity": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "value": {
                        "type": "string"
                      }
                    }
                  },
                  "name": {
                    "type": "string"
                  },
                  "createdComment": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "entityType": "lead",
                "entity": {
                  "type": "entityId",
                  "value": "503"
                },
                "name": "New - Lead Not Viewed",
                "createdComment": "New leads must be contacted within 4 business hours. Please visit your lead record and log a call with your customer to resolve this alert."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Create an Alert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "uuid": {
                      "type": "string"
                    },
                    "entityType": {
                      "type": "string"
                    },
                    "entityId": {
                      "type": "integer"
                    },
                    "name": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "creationUserType": {
                      "type": "string"
                    },
                    "createdByUserId": {
                      "type": "null"
                    },
                    "creationType": {
                      "type": "string"
                    },
                    "resolveType": {
                      "type": "string"
                    },
                    "metricKey": {
                      "type": "string"
                    },
                    "metricValue": {
                      "type": "string"
                    },
                    "createdComment": {
                      "type": "string"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "resolvedComment": {
                      "type": "null"
                    },
                    "resolvedByUserId": {
                      "type": "null"
                    },
                    "resolvedDate": {
                      "type": "null"
                    },
                    "createdDate": {
                      "type": "string"
                    },
                    "updatedDate": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "id": 10,
                  "uuid": "d73c51c5-3fbe-4d8e-8f24-2ecce2f8e8e1",
                  "entityType": "booking",
                  "entityId": 1,
                  "name": "Technician unavailable",
                  "status": "active",
                  "creationUserType": "integration_api",
                  "createdByUserId": null,
                  "creationType": "manual",
                  "resolveType": "manual",
                  "metricKey": "capacity",
                  "metricValue": "0",
                  "createdComment": "Created from external monitoring",
                  "reference": "EXT-ALERT-100",
                  "resolvedComment": null,
                  "resolvedByUserId": null,
                  "resolvedDate": null,
                  "createdDate": "2026-02-24T10:00:00.000Z",
                  "updatedDate": "2026-02-24T10:00:00.000Z"
                }
              }
            }
          }
        }
      }
    },
    "/api/integration/alert/resolve": {
      "patch": {
        "operationId": "alertsResolveAlert",
        "summary": "Resolve Alert",
        "description": "## General Description\n\nResolves an existing alert by `alertId` or `alertReference`.\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationResolveAlertRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `alert` | `ExternalIntegrationAlertIdentifierRequestDTO` | Yes | Alert identifier object. |\n| `resolvedComment` | string | No | Optional resolution comment. |\n\n### `ExternalIntegrationAlertIdentifierRequestDTO`\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | `alertId` or `alertReference`. |\n| `value` | string | Yes | ID or reference value according to `type`. |\n\n* * *\n\n## Example Request\n\n```json\n{\n  \"alert\": {\n    \"type\": \"alertReference\",\n    \"value\": \"EXT-ALERT-100\"\n  },\n  \"resolvedComment\": \"Issue solved by integration workflow.\"\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\n\n```\n\n```json\n{\n  \"id\": 10,\n  \"uuid\": \"d73c51c5-3fbe-4d8e-8f24-2ecce2f8e8e1\",\n  \"entityType\": \"booking\",\n  \"entityId\": 12345,\n  \"name\": \"Technician unavailable\",\n  \"status\": \"resolved\",\n  \"creationUserType\": \"integration_api\",\n  \"createdByUserId\": null,\n  \"creationType\": \"manual\",\n  \"resolveType\": \"manual\",\n  \"metricKey\": \"capacity\",\n  \"metricValue\": \"0\",\n  \"createdComment\": \"Created from external monitoring\",\n  \"reference\": \"EXT-ALERT-100\",\n  \"resolvedComment\": \"Issue solved by integration workflow.\",\n  \"resolvedByUserId\": null,\n  \"resolvedDate\": \"2026-02-24T10:30:00.000Z\",\n  \"createdDate\": \"2026-02-24T10:00:00.000Z\",\n  \"updatedDate\": \"2026-02-24T10:30:00.000Z\"\n}\n\n```\n\n## Example Error Responses\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"INVALID_ALERT_IDENTIFIER_TYPE\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"ONLY_ACTIVE_ALERT_CAN_BE_RESOLVED\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"STICKY_ALERT_CANNOT_BE_RESOLVED\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 404,\n  \"message\": \"ALERT_NOT_FOUND\",\n  \"error\": \"Not Found\"\n}\n\n```\n\n# Business Rules & Constraints\n\n-   `alert.type` must be `alertId` or `alertReference`; otherwise returns `INVALID_ALERT_IDENTIFIER_TYPE`.\n    \n-   If identifier is missing/empty after normalization, backend returns `ALERT_IDENTIFIER_REQUIRED`.\n    \n-   Only alerts with status `active` can be resolved: otherwise `ONLY_ACTIVE_ALERT_CAN_BE_RESOLVED`.\n    \n-   Alerts with `resolveType = sticky` cannot be resolved via API: `STICKY_ALERT_CANNOT_BE_RESOLVED`.\n    \n-   If alert does not exist: `ALERT_NOT_FOUND`.",
        "tags": [
          "Alerts"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resolve Alert"
          }
        }
      }
    },
    "/api/integration/alert/reopen": {
      "patch": {
        "operationId": "alertsReopenAlert",
        "summary": "Reopen Alert",
        "description": "## General Description\n\nReopens a resolved alert by `alertId` or `alertReference`.\n\n* * *\n\n## Field Definitions\n\n### Request Body: ExternalIntegrationReopenAlertRequestDTO\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `alert` | `ExternalIntegrationAlertIdentifierRequestDTO` | Yes | Alert identifier object. |\n\n### `ExternalIntegrationAlertIdentifierRequestDTO`\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | enum | Yes | `alertId` or `alertReference`. |\n| `value` | string | Yes | ID or reference value according to `type`. |\n\n* * *\n\n## Example Request\n\n```json\n{\n  \"alert\": {\n    \"type\": \"alertId\",\n    \"value\": \"10\"\n  }\n}\n\n```\n\n## Example Response\n\n```http\nHTTP/1.1 200 OK\n\n```\n\n```json\n{\n  \"id\": 10,\n  \"uuid\": \"d73c51c5-3fbe-4d8e-8f24-2ecce2f8e8e1\",\n  \"entityType\": \"booking\",\n  \"entityId\": 12345,\n  \"name\": \"Technician unavailable\",\n  \"status\": \"active\",\n  \"creationUserType\": \"integration_api\",\n  \"createdByUserId\": null,\n  \"creationType\": \"manual\",\n  \"resolveType\": \"manual\",\n  \"metricKey\": \"capacity\",\n  \"metricValue\": \"0\",\n  \"createdComment\": \"Created from external monitoring\",\n  \"reference\": \"EXT-ALERT-100\",\n  \"resolvedComment\": \"Issue solved by integration workflow.\",\n  \"resolvedByUserId\": null,\n  \"resolvedDate\": \"2026-02-24T10:30:00.000Z\",\n  \"createdDate\": \"2026-02-24T10:00:00.000Z\",\n  \"updatedDate\": \"2026-02-24T11:00:00.000Z\"\n}\n\n```\n\n## Example Error Responses\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"INVALID_ALERT_IDENTIFIER_TYPE\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"ONLY_RESOLVED_ALERT_CAN_BE_REOPENED\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"STICKY_ALERT_CANNOT_BE_REOPENED\",\n  \"error\": \"Bad Request\"\n}\n\n```\n\n```json\n{\n  \"statusCode\": 404,\n  \"message\": \"ALERT_NOT_FOUND\",\n  \"error\": \"Not Found\"\n}\n\n```\n\n* * *\n\n# Business Rules & Constraint\n\n-   `alert.type` must be `alertId` or `alertReference`; otherwise returns `INVALID_ALERT_IDENTIFIER_TYPE`.\n    \n-   If identifier is missing/empty after normalization, backend returns `ALERT_IDENTIFIER_REQUIRED`.\n    \n-   Only alerts with status `resolved` can be reopened: otherwise `ONLY_RESOLVED_ALERT_CAN_BE_REOPENED`.\n    \n-   Alerts with `resolveType = sticky` cannot be reopened via API: `STICKY_ALERT_CANNOT_BE_REOPENED`.\n    \n-   If alert does not exist: `ALERT_NOT_FOUND`.",
        "tags": [
          "Alerts"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reopen Alert"
          }
        }
      }
    },
    "/api/integration/catalog/categories": {
      "get": {
        "operationId": "catalogActiveCategories",
        "summary": "Active categories",
        "tags": [
          "Catalog"
        ],
        "parameters": [
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Active categories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "integer"
                      },
                      "name": {
                        "type": "string"
                      },
                      "active": {
                        "type": "boolean"
                      }
                    }
                  }
                },
                "example": [
                  {
                    "id": 98,
                    "name": "Assembly",
                    "active": true
                  },
                  {
                    "id": 103,
                    "name": "Cortinas Roller",
                    "active": true
                  },
                  {
                    "id": 101,
                    "name": "Pisos",
                    "active": true
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/integration/catalog/categories/{categoryId}/services": {
      "get": {
        "operationId": "catalogActiveServicesByCategory",
        "summary": "Active services by category",
        "tags": [
          "Catalog"
        ],
        "parameters": [
          {
            "name": "categoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Active variants by category",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "integer"
                      },
                      "name": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "order": {
                        "type": "integer"
                      },
                      "image": {
                        "type": "string"
                      },
                      "variants": {
                        "type": "array",
                        "items": {}
                      },
                      "categories": {
                        "type": "array",
                        "items": {}
                      },
                      "created_date": {
                        "type": "string"
                      },
                      "active": {
                        "type": "boolean"
                      }
                    }
                  }
                },
                "example": [
                  {
                    "id": 113,
                    "name": "Servicio de prueba integración",
                    "description": "descripción de prueba",
                    "order": 0,
                    "image": "",
                    "variants": [],
                    "categories": [],
                    "created_date": "2024-01-29T11:14:51.317Z",
                    "active": true
                  },
                  {
                    "id": 132,
                    "name": "Instalación de cortinas",
                    "description": "Instalar cortinas de casa",
                    "order": 0,
                    "image": "",
                    "variants": [],
                    "categories": [],
                    "created_date": "2024-05-20T10:31:35.230Z",
                    "active": true
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/catalog/services/{serviceId}/variants": {
      "get": {
        "operationId": "catalogActiveVariantsByService",
        "summary": "Active variants by service",
        "tags": [
          "Catalog"
        ],
        "parameters": [
          {
            "name": "serviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Active variants by service and category",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "integer"
                      },
                      "internal_name": {
                        "type": "string"
                      },
                      "service": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "serviceType": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      },
                      "skus": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "sku": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": [
                  {
                    "id": 284,
                    "internal_name": "Variante de Servicio- Corto",
                    "service": {
                      "id": 137,
                      "name": "Servicio de Pruebas - Corto",
                      "serviceType": {
                        "id": 1,
                        "name": "B1"
                      }
                    },
                    "skus": [
                      {
                        "id": 461,
                        "sku": "sku-ucdev-7"
                      }
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/integration/unified/upsert": {
      "post": {
        "operationId": "configurationUpsertVariantsAndProviders",
        "summary": "Upsert variants and providers",
        "description": "### **Purpose**\n\nCreates or updates service variants and providers (professionals) in a single API call.\n\nThis endpoint manages the complete lifecycle of service variants identified by SKU, providers identified by reference, and their associated configurations including provider-variant associations, availability schedules, and working areas.\n\nThe endpoint processes **execution variants only** (not budgeted variants).\n\nThis endpoint is specifically designed for external integration systems to synchronize professional data and service configurations. It supports creating or updating professionals that are either natural persons or networks, but **must not** be used for technicians that belong to a company.\n\n* * *\n\n### **Field Definitions**\n\n#### 🗂️ **Request Body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `providers` | `array[object]` | ❌ | Array of provider objects to create or update. If omitted, only variants will be processed. |\n| `variants` | `array[object]` | ❌ | Array of service variant objects to create or update. If omitted, only providers will be processed. |\n\n* * *\n\n#### 👷 **Provider**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `reference` | `string` | ✅ | Unique reference identifier for the provider. Used to identify existing providers for updates. |\n| `status` | `string` | ❌ | Status for the provider. If not included, default status for new provider is `accepted`. If included, must be `accepted` or `rejected`. |\n| `basicInformation` | `object` | ✅ | Basic user information for the provider. See **Provider Basic Information** below. |\n| `workOnHolidays` | `boolean` | ❌ | Whether the provider works on holidays. Defaults to **false** if not provided. |\n| `isCompany` | `boolean` | ❌ | Whether the provider is a company. Defaults to **false** if not provided. |\n| `isMainProviderEligible` | `boolean` | ❌ | Whether the provider is eligible to be assigned as the main provider. Defaults to **true** if not provided. |\n| `isLeadAssignmentEligible` | `boolean` | ❌ | Whether the provider is eligible for lead assignment. Defaults to **true** if not provided. |\n| `service_variants` | `array[object]` | ❌ | Array of service variants associated with this provider. Variants can be referenced by ID or SKU. |\n| `availability` | `array[object]` | ❌ | Array of availability schedules defining when the provider is available. |\n| `areas` | `array[object]` | ❌ | Array of working areas where the provider operates. Areas can be referenced by ID or reference. |\n\n* * *\n\n#### 🪪 **Provider Basic Information**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `basicInformation.name` | `string` | ✅ | Provider's first name. |\n| `basicInformation.lastName` | `string` | ✅ | Provider's last name. |\n| `basicInformation.phoneNumber` | `string` | ✅ | Provider's phone number. |\n| `basicInformation.email` | `string` | ✅ | Provider's email address. Must be unique in the system. |\n| `basicInformation.identificationNumber` | `string` | ✅ | Provider's identification number (e.g., national ID, passport). |\n| `basicInformation.identificationNumberCountry` | `string` | ✅ | Country code for the identification number. |\n| `basicInformation.reference` | `string` | ❌ | Optional reference identifier (separate from provider reference). |\n\n* * *\n\n#### 📅 **Provider Availability**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `availability[].day_of_week` | `number` | ✅ | Day of the week (0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday). |\n| `availability[].start_time` | `string` | ✅ | Start time in HH:mm format (e.g., `\"09:00\"`). |\n| `availability[].end_time` | `string` | ✅ | End time in HH:mm format (e.g., `\"17:00\"`). |\n\n> **Availability is fully replaced** on update. All previous availability records are deleted and replaced by the incoming set.\n\n* * *\n\n#### 🗺️ **Provider Areas**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `areas[].type` | `string` | ✅ | Type of area identifier. Must be one of: `\"areaId\"` or `\"areaReference\"`. |\n| `areas[].value` | `string` | ✅ | The area ID (if type is `\"areaId\"`) or area reference (if type is `\"areaReference\"`). |\n| `areas[].variantCoverage` | `array[object]` | ❌ | Optional list of service variants covered by this provider **specifically in this area** (differentiated coverage). When omitted or empty, the provider covers **all** their assigned variants in this area (total coverage). |\n| `areas[].variantCoverage[].type` | `string` | ✅ when variantCoverage sent | Type of variant identifier. Must be one of: `\"variantId\"` or `\"variantSku\"`. |\n| `areas[].variantCoverage[].value` | `string` | ✅ when variantCoverage sent | The variant ID (if type is `\"variantId\"`) or SKU (if type is `\"variantSku\"`). |\n\n> When `variantCoverage` is provided for an area, only the listed variants will be restricted to that specific working area. Variants not listed in any `variantCoverage` entry retain total coverage (unrestricted).\n\n* * *\n\n#### 🔧 **Variant**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `sku` | `string` | ✅ | Stock Keeping Unit identifier. Must be unique across all variants. Used to identify existing variants for updates. |\n| `name` | `string` | ✅ | Internal name of the service variant. |\n| `isInStore` | `boolean` | ✅ | Whether this variant is available for in-store services. |\n| `isExecution` | `boolean` | ✅ | Whether this is an execution variant. Only execution variants (`true`) are processed by this endpoint. Budget variants (`false`) are skipped. |\n| `parentService` | `object` | ✅ | Parent service information. If the service or category doesn't exist, it will be created. See **Parent Service** below. |\n| `operationAreas` | `object` | ❌ | Operation area configurations with `detailed` (specific areas) and/or `all` (default parameters for remaining areas). |\n\n* * *\n\n#### 🏷️ **Parent Service**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `parentService.name` | `string` | ✅ | Name of the service. Matching is done using normalized string comparison (case-insensitive, accent-insensitive). |\n| `parentService.description` | `string` | ❌ | Description of the service. |\n| `parentService.category.name` | `string` | ✅ | Name of the category. Matching is done using normalized string comparison (case-insensitive, accent-insensitive). |\n| `parentService.category.description` | `string` | ❌ | Description of the category. |\n\n* * *\n\n#### 🗺️ **Operation Areas**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `operationAreas.all` | `object` | ❌ | Default parameters applied to all active areas not explicitly covered by `detailed`. Allows setting default pricing and duration for all remaining areas. |\n| `operationAreas.detailed` | `array[object]` | ❌ | Array of specific operation area configurations. Each entry defines pricing, duration, and area coverage for specific areas. `detailed` entries take precedence over `all`. |\n| `operationAreas.detailed[].type` | `string` | ✅ when detailed sent | Type of area identifier. Must be one of: `\"areaId\"` or `\"areaReference\"`. |\n| `operationAreas.detailed[].value` | `array[string]` | ✅ when detailed sent | Array of area identifiers. Areas are automatically grouped by currency for operation variant creation. |\n| `operationAreas.detailed[].duration` | `string` | ❌ | Duration of the operation in minutes (as a string, e.g., `\"60\"`). |\n| `operationAreas.detailed[].bookingAnticipationHours` | `number` | ❌ | Number of hours in advance a booking must be made for this operation. |\n| `operationAreas.detailed[].price` | `number` | ❌ | Price for this operation variant. |\n| `operationAreas.detailed[].cost` | `number` | ❌ | Cost for this operation variant. |\n| `operationAreas.detailed[].requireEvidence` | `boolean` | ❌ | Whether evidence is required for this operation. |\n| `operationAreas.detailed[].requireSignature` | `boolean` | ❌ | Whether a signature is required for this operation. |\n| `operationAreas.all.duration` | `string` | ❌ | Default duration in minutes (as a string, e.g., `\"60\"`). Applied to all remaining areas not covered by `detailed`. |\n| `operationAreas.all.bookingAnticipationHours` | `number` | ❌ | Default number of hours in advance a booking must be made. Applied to all remaining areas not covered by `detailed`. |\n| `operationAreas.all.price` | `number` | ❌ | Default price. Applied to all remaining areas not covered by `detailed`. |\n| `operationAreas.all.cost` | `number` | ❌ | Default cost. Applied to all remaining areas not covered by `detailed`. |\n| `operationAreas.all.requireEvidence` | `boolean` | ❌ | Default requirement for evidence. Applied to all remaining areas not covered by `detailed`. |\n| `operationAreas.all.requireSignature` | `boolean` | ❌ | Default requirement for signature. Applied to all remaining areas not covered by `detailed`. |\n\n* * *\n\n### **Example Request**\n\n```json\n{\n  \"variants\": [\n    {\n      \"sku\": \"SV-001\",\n      \"name\": \"Standard Cleaning Service\",\n      \"isInStore\": false,\n      \"isExecution\": true,\n      \"parentService\": {\n        \"name\": \"Cleaning Services\",\n        \"description\": \"Professional cleaning services\",\n        \"category\": {\n          \"name\": \"Home Services\",\n          \"description\": \"Services for home maintenance\"\n        }\n      },\n      \"operationAreas\": {\n        \"detailed\": [\n          {\n            \"type\": \"areaReference\",\n            \"value\": [\"AREA-001\", \"AREA-002\"],\n            \"duration\": \"120\",\n            \"price\": 150.0,\n            \"cost\": 100.0,\n            \"bookingAnticipationHours\": 24\n          }\n        ],\n        \"all\": {\n          \"duration\": \"60\",\n          \"price\": 100.0,\n          \"cost\": 50.0,\n          \"bookingAnticipationHours\": 12\n        }\n      }\n    }\n  ],\n  \"providers\": [\n    {\n      \"reference\": \"PROV-001\",\n      \"basicInformation\": {\n        \"name\": \"John\",\n        \"lastName\": \"Doe\",\n        \"email\": \"john.doe@example.com\",\n        \"phoneNumber\": \"+1234567890\",\n        \"identificationNumber\": \"12345678\",\n        \"identificationNumberCountry\": \"US\"\n      },\n      \"isCompany\": false,\n      \"workOnHolidays\": false,\n      \"isMainProviderEligible\": true,\n      \"isLeadAssignmentEligible\": true,\n      \"service_variants\": [\n        {\n          \"type\": \"variantSku\",\n          \"value\": \"SV-001\"\n        },\n        {\n          \"type\": \"variantSku\",\n          \"value\": \"SV-002\"\n        }\n      ],\n      \"availability\": [\n        {\n          \"day_of_week\": 1,\n          \"start_time\": \"09:00\",\n          \"end_time\": \"17:00\"\n        },\n        {\n          \"day_of_week\": 2,\n          \"start_time\": \"09:00\",\n          \"end_time\": \"17:00\"\n        }\n      ],\n      \"areas\": [\n        {\n          \"type\": \"areaReference\",\n          \"value\": \"AREA-001\"\n        },\n        {\n          \"type\": \"areaReference\",\n          \"value\": \"AREA-002\",\n          \"variantCoverage\": [\n            {\n              \"type\": \"variantSku\",\n              \"value\": \"SV-001\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\n```\n\nIn this example, the provider covers `AREA-001` with **total coverage** (all their variants) and `AREA-002` with **differentiated coverage** restricted to `SV-001` only.\n\n* * *\n\n### **Response Example**\n\n```json\n{\n  \"success\": true,\n  \"message\": \"All operations completed successfully\",\n  \"variantsProcessed\": 1,\n  \"providersProcessed\": 1,\n  \"variantResults\": [\n    {\n      \"variantId\": 123,\n      \"sku\": \"SV-001\",\n      \"success\": true\n    }\n  ],\n  \"providerResults\": [\n    {\n      \"providerId\": 456,\n      \"reference\": \"PROV-001\",\n      \"success\": true\n    }\n  ]\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `boolean` | Indicates whether all operations completed successfully. |\n| `message` | `string` | Human-readable message describing the operation result. |\n| `variantsProcessed` | `number` | Number of variants successfully processed. |\n| `providersProcessed` | `number` | Number of providers successfully processed. |\n| `errors` | `array[string]` | Array of error messages if any operations failed. Each message includes the identifier (SKU or reference) and the error description. |\n| `variantResults` | `array[object]` | Detailed processing results for each variant. |\n| `variantResults[].variantId` | `number` | The ID of the variant that was processed. |\n| `variantResults[].sku` | `string` | The SKU identifier of the variant. |\n| `variantResults[].success` | `boolean` | Whether this specific variant was processed successfully. |\n| `variantResults[].error` | `string` | Error message if the variant processing failed. Only present when `success` is `false`. |\n| `providerResults` | `array[object]` | Detailed processing results for each provider. |\n| `providerResults[].providerId` | `number` | The ID of the provider that was processed. |\n| `providerResults[].reference` | `string` | The reference identifier of the provider. |\n| `providerResults[].success` | `boolean` | Whether this specific provider was processed successfully. |\n| `providerResults[].error` | `string` | Error message if the provider processing failed. Only present when `success` is `false`. |\n\n* * *\n\n### **Error Response Example**\n\n```json\n{\n  \"success\": false,\n  \"message\": \"Completed with 2 error(s)\",\n  \"variantsProcessed\": 0,\n  \"providersProcessed\": 1,\n  \"errors\": [\n    \"Variant SV-001: Multiple variants found for the same SKU\",\n    \"Provider PROV-002: Provider cannot be part of a network\"\n  ],\n  \"variantResults\": [\n    {\n      \"variantId\": 0,\n      \"sku\": \"SV-001\",\n      \"success\": false,\n      \"error\": \"Multiple variants found for the same SKU\"\n    }\n  ],\n  \"providerResults\": [\n    {\n      \"providerId\": 456,\n      \"reference\": \"PROV-001\",\n      \"success\": true\n    },\n    {\n      \"providerId\": 0,\n      \"reference\": \"PROV-002\",\n      \"success\": false,\n      \"error\": \"Provider cannot be part of a network\"\n    }\n  ]\n}\n\n```\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Description |\n| --- | --- |\n| `400 Bad Request` | One or more required fields are missing or invalid. |\n| `401 Unauthorized` | Authentication token missing or expired. |\n| `403 Forbidden` | The API key or origin is not authorized. |\n| `404 Not Found` | A referenced variant, provider, or area could not be found. |\n| `500 Internal Server Error` | Unexpected server error. Contact Sodtrack support. |\n\n* * *\n\n# Business Rules & Constraints\n\n## Provider Type Restrictions\n\n-   This endpoint only supports creating or updating professionals that are either:\n    \n    -   **Natural persons** (individual providers with `isCompany: false` and no parent relationship)\n        \n    -   **Networks** (providers with `isCompany: true` that act as parent organizations)\n        \n-   It **MUST NOT** be used to create or update technicians that belong to a company (providers with a `parent` relationship). Attempting to update a provider that has an existing parent relationship will result in an error.\n    \n\n* * *\n\n## Variant SKU Uniqueness\n\n-   Each service variant SKU sent in the request **MUST be unique** in the system.\n    \n-   If more than one variant is found for the same SKU, the operation for that SKU **must fail** and be stored as an error.\n    \n-   No partial processing occurs for that SKU — the entire variant upsert operation for that SKU is rejected.\n    \n\n* * *\n\n## Service and Category Changes\n\n-   If a SKU in the variants payload matches an existing variant, but the service or category differs from the existing one:\n    \n    -   The variant and all its operation variants will be **moved** from the existing service to the new service provided in the request.\n        \n    -   If the category also differs, the variant will be moved under the new category.\n        \n    -   This operation **preserves** all existing operation variants and their configurations — only the service and category associations are updated.\n        \n\n* * *\n\n## Operation Variants Preservation\n\n-   **Operation variants are NEVER deleted** by the algorithm. The system preserves all existing operation variants and only updates or reassigns them based on the incoming payload.\n    \n-   **Operation variants NEVER end without being associated to an operation area.** The re-shuffle logic ensures all operation variants maintain at least one area association.\n    \n\n* * *\n\n## Execution Variants Only\n\n-   Only variants with `isExecution: true` are processed. Variants with `isExecution: false` are skipped with a warning log entry and do not count toward the `variantsProcessed` total.\n\n* * *\n\n## Differentiated Area Coverage (`variantCoverage`)\n\n`variantCoverage` configures a **restriction on the variant**, not on the area. All areas in `provider.areas` are always associated to the provider as working areas, regardless of whether they carry a `variantCoverage` or not.\n\n**How it works:**\n\n-   Variants listed in `variantCoverage` for an area are **restricted to operate only in that area**. Their provider-variant association is linked specifically to that working area. If the same variant appears in `variantCoverage` across multiple areas, it is restricted to **all of those areas combined**.\n    \n-   Variants with no `variantCoverage` entry anywhere have **total coverage** — they operate across all working areas of the provider.\n    \n-   A variant listed in `variantCoverage` but absent from `service_variants` is automatically added as a new provider-variant association with its area restriction.\n    \n\n> **Important**: if the same variant appears in both `service_variants` and in a `variantCoverage` entry, the restriction takes effect — the variant will be limited to that area and will **not** have total coverage.\n\n**Delete behavior:**\n\n-   Deletion of provider-variant associations only runs when `service_variants` is explicitly provided.\n    \n-   Only associations absent from **both** `service_variants` **and** all `variantCoverage` entries across all areas are removed.\n    \n\n* * *\n\n## Update Strategy\n\nWhen a provider is sent and it already exists (identified by `reference`), the update follows this pattern:\n\n### workingAreas (`areas` field)\n\n-   **Keep**: Working areas that match areas in the incoming `areas` array are preserved.\n    \n-   **Remove**: Working areas that exist but are not in the incoming `areas` array are deleted.\n    \n-   **Add**: New working areas are created for areas in the incoming `areas` array that don't have an existing working area association.\n    \n\n### availabilities (`availability` field)\n\n-   **Replace All**: All existing availabilities are deleted and replaced by the new set provided in the `availability` array.\n\n### professionalServiceVariants (`service_variants` field)\n\n-   **If** **`service_variants`** **is omitted**: Existing provider-variant associations are left untouched. Only `variantCoverage` entries (from `areas`) may implicitly add new associations or update working-area restrictions on existing ones.\n    \n-   **If** **`service_variants`** **is provided**: The existing associations are fully reconciled against the incoming list:\n    \n    -   **Keep**: Associations that match variants in the incoming `service_variants` array (or `variantCoverage` entries) are preserved.\n        \n    -   **Remove**: Associations absent from both `service_variants` and all `variantCoverage` entries are deleted.\n        \n    -   **Add**: New associations are created for variants in `service_variants` or `variantCoverage` entries that don't have an existing association.\n        \n\n> Provider basic information fields (`isMainProviderEligible`, `isLeadAssignmentEligible`, `workOnHolidays`) are updated directly from the payload values. The `isCompany` field is only set during creation and is **not updated** for existing providers.\n\n* * *\n\n## Operation Variants Re-shuffle Logic\n\nWhen an existing service variant is sent with operation area configurations (via the `operationAreas` object), the system performs intelligent re-shuffling of operation variants rather than deleting and recreating them. The algorithm supports two configuration modes: `detailed` (specific area configurations) and `all` (default parameters for remaining areas).\n\n### Processing Flow\n\nThe system processes operation areas in two phases:\n\n#### Phase 1: Processing `detailed` Entries\n\n1.  **Area Resolution and Currency Grouping**\n    \n    -   Each area value in each `detailed` entry is resolved to an Area entity with its associated currency.\n        \n    -   Areas are automatically grouped by currency — one VariantOperation is created or updated per currency group.\n        \n    -   The system tracks which areas have been processed in this phase.\n        \n2.  **Conflict Detection**\n    \n    -   For each currency group, the system identifies existing operation variants that have overlapping areas (same currency, shared area IDs).\n        \n    -   If no conflicts exist, a new operation variant is created with the specified areas and parameters.\n        \n3.  **Conflict Resolution Strategy**\n    \n    -   **Operations with Remaining Areas**: If an existing operation variant has both overlapping areas (to be reassigned) and non-overlapping areas (to remain), the system:\n        \n        -   Removes the overlapping areas from the existing operation variant\n            \n        -   Updates the operation variant to keep only the remaining areas\n            \n        -   Preserves the existing operation variant's parameters (duration, cost, price, etc.)\n            \n        -   The freed overlapping areas are added to the working set for reassignment\n            \n4.  **Operations That Would Become Empty**\n    \n    -   If an existing operation variant would become empty (all its areas are being reassigned), the system:\n        \n        -   Sorts these operations by area count (fewest first) for deterministic processing\n            \n        -   Updates all but the last operation with the new parameters and keeps their existing areas\n            \n        -   Removes these areas from the working set\n            \n        -   Updates the last operation with the new parameters and assigns all remaining areas from the working set to it\n            \n5.  **New Operation Creation**\n    \n    -   If any areas remain in the working set after conflict resolution, a new operation variant is created with those areas and the specified parameters.\n\n#### Phase 2: Processing `all` Parameters (if provided)\n\n1.  **Remaining Areas Identification**\n    \n    -   The system retrieves all active areas in the system.\n        \n    -   It filters out areas already processed in Phase 1 (from `detailed` entries).\n        \n2.  **Synthetic DTO Creation**\n    \n    -   For the remaining areas, the system creates synthetic area configurations using the parameters from the `all` configuration.\n3.  **Processing Remaining Areas**\n    \n    -   The synthetic configurations are processed using the same conflict resolution logic as Phase 1.\n        \n    -   This ensures all remaining areas receive the default parameters specified in `all`.\n        \n\n### Key Principles\n\n-   **No Deletion**: Operation variants are never deleted. They are either updated with new areas/parameters or preserved as-is.\n    \n-   **Area Preservation**: All areas specified in the request (either explicitly in `detailed` or implicitly via `all`) are assigned to operation variants — no areas are lost.\n    \n-   **Parameter Updates**: When an operation variant is updated, its parameters (duration, cost, price, bookingAnticipationHours) are updated to match the incoming values.\n    \n-   **Currency Isolation**: Operation variants are always grouped by currency. Areas with different currencies are never mixed in the same operation variant.\n    \n-   **Priority**: `detailed` entries take precedence over `all`. Areas specified in `detailed` are processed first, and `all` parameters are only applied to areas not covered by `detailed`.\n    \n\n### Usage Patterns\n\n#### Pattern 1: Detailed Configuration Only\n\nUse `detailed` when you need specific configurations for specific areas:\n\n```json\n{\n  \"operationAreas\": {\n    \"detailed\": [\n      {\n        \"type\": \"areaReference\",\n        \"value\": [\"AREA-001\", \"AREA-002\"],\n        \"price\": 150.0,\n        \"duration\": \"120\"\n      }\n    ]\n  }\n}\n\n```\n\n#### Pattern 2: All Areas with Default Parameters\n\nUse `all` when you want to apply the same parameters to all active areas:\n\n```json\n{\n  \"operationAreas\": {\n    \"all\": {\n      \"price\": 100.0,\n      \"duration\": \"60\",\n      \"cost\": 50.0\n    }\n  }\n}\n\n```\n\n#### Pattern 3: Mixed Configuration (Recommended)\n\nUse both `detailed` and `all` when you need specific configurations for some areas and default parameters for the rest:\n\n```json\n{\n  \"operationAreas\": {\n    \"detailed\": [\n      {\n        \"type\": \"areaReference\",\n        \"value\": [\"AREA-001\"],\n        \"price\": 200.0,\n        \"duration\": \"180\"\n      }\n    ],\n    \"all\": {\n      \"price\": 100.0,\n      \"duration\": \"60\"\n    }\n  }\n}\n\n```\n\nIn this example, `AREA-001` gets the specific configuration (price: 200.0, duration: 180), while all other active areas get the default parameters (price: 100.0, duration: 60).\n\n### Example Scenario\n\n**Existing State:**\n\n-   Operation Variant A: Areas \\[1, 2, 3\\], Currency USD, Price $100\n    \n-   Operation Variant B: Areas \\[4, 5\\], Currency USD, Price $80\n    \n-   System has 10 total active areas: \\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\]\n    \n\n**Incoming Request:**\n\n```json\n{\n  \"operationAreas\": {\n    \"detailed\": [\n      {\n        \"type\": \"areaId\",\n        \"value\": [\"2\", \"3\", \"6\"],\n        \"price\": 120.0,\n        \"duration\": \"90\"\n      }\n    ],\n    \"all\": {\n      \"price\": 80.0,\n      \"duration\": \"60\"\n    }\n  }\n}\n\n```\n\n**Result:**\n\n-   Operation Variant A: Updated to Areas \\[1\\], Currency USD, Price $100 (areas 2, 3 removed; price preserved since not in `detailed`)\n    \n-   Operation Variant B: Updated to Areas \\[4, 5\\], Currency USD, Price $80 (parameters updated from `all`)\n    \n-   New Operation Variant C: Areas \\[2, 3, 6\\], Currency USD, Price $120, Duration 90 (created from `detailed`)\n    \n-   New Operation Variant D: Areas \\[7, 8, 9, 10\\], Currency USD, Price $80, Duration 60 (created from `all` for remaining areas)",
        "tags": [
          "Configuration"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Upsert variants and providers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "variantsProcessed": {
                      "type": "integer"
                    },
                    "providersProcessed": {
                      "type": "integer"
                    },
                    "variantResults": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "variantId": {
                            "type": "integer"
                          },
                          "sku": {
                            "type": "string"
                          },
                          "success": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "providerResults": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "providerId": {
                            "type": "integer"
                          },
                          "reference": {
                            "type": "string"
                          },
                          "success": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "message": "All operations completed successfully",
                  "variantsProcessed": 1,
                  "providersProcessed": 1,
                  "variantResults": [
                    {
                      "variantId": 123,
                      "sku": "SV-001",
                      "success": true
                    }
                  ],
                  "providerResults": [
                    {
                      "providerId": 456,
                      "reference": "PROV-001",
                      "success": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "One or more required fields are missing or invalid."
          },
          "401": {
            "description": "Authentication token missing or expired."
          },
          "403": {
            "description": "The API key or origin is not authorized."
          },
          "404": {
            "description": "A referenced variant, provider, or area could not be found."
          },
          "500": {
            "description": "Unexpected server error. Contact Sodtrack support."
          }
        }
      }
    },
    "/api/integration/coverage/check": {
      "get": {
        "operationId": "coverageCoverageByGeographicalReferenceAndSkuOrVariantId",
        "summary": "Coverage by geographical reference and sku or variant id",
        "tags": [
          "Coverage"
        ],
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lng",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "variantId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sku",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Coverage by geographical reference and variant id",
            "content": {
              "application/json": {
                "schema": {
                  "type": "boolean"
                },
                "example": true
              }
            }
          }
        }
      }
    },
    "/api/integration/dates/check": {
      "post": {
        "operationId": "coverageAvailableDates",
        "summary": "Available Dates",
        "description": "### **Purpose**\n\nRetrieves the available **dates** for performing a specific service, based on the requested **location**, **service variant**, and optional **provider** parameters.\n\nThis endpoint allows client systems to display valid scheduling options to customers, ensuring that the selected date corresponds to Sodtrack’s real-time contractor availability.\n\n#### **Field Definitions**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `location` | `object` | ✅ | Defines the geographical reference for checking service availability. |\n| `location.type` | `string` | ✅ | Determines how the location is identified. Accepted values:  \n• `\"coordinates\"` — Uses geographic coordinates.  \n• `\"areaId\"` — Uses the internal Sodtrack area identifier.  \n• `\"areaReference\"` — Uses the SKU associated with a predefined service area. |\n| `location.value` | `object` or `number` or `string` | ✅ | The value corresponding to the selected `location.type`:  \n  \n**If** **`type = \"coordinates\"`** → must be an **object**:  \n`{ \"lat\": number, \"lng\": number }`  \n  \n**If** **`type = \"areaReferenceId\"`** → must be a **number** representing the internal area ID.  \n  \n**If** **`type = \"areaReference\"`** → must be a **string** representing the area Reference. |\n| `variant` | `object` | ✅ | Identifies the specific service variant to check availability for. |\n| `variant.type` | `string` | ✅ | Type of variant identifier. Options: `\"variantSku\"` or `\"variantId\"`. |\n| `variant.value` | `string` | ✅ | The SKU or ID of the variant, matching the selected `variant.type`. |\n| `provider` | `object` | ❌ | (Optional) Restricts availability to a specific contractor. |\n| `provider.type` | `string` | ❌ | Type of provider identifier. Options: `\"providerId\"` or `\"providerReference\"`. |\n| `provider.value` | `string` | ❌ | The corresponding provider ID or external reference. |\n| `startDate` | `string` | ❌ | The first date (inclusive) to begin checking for availability. Format: `YYYY-MM-DD`. Default: current date. |\n| `quantityOfDays` | `number` | ❌ | Number of consecutive days (from `startDate`) to check for availability. Default: `5`. |\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `dates` | `array[string]` | List of available dates (in `YYYY-MM-DD` format) where the service can be scheduled. |\n\n### **Error Responses**\n\n| HTTP Status | Error Code / Key | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | Missing or invalid request parameters. |\n| `401 Unauthorized` | — | Missing or expired authentication token. |\n| `403 Forbidden` | — | The API key or origin is not authorized to access this resource. |\n| `404 Not Found` | — | The specified variant or provider does not exist or is not linked to the given location. |\n| `500 Internal Server Error` | — | Unexpected server error. Contact support if the issue persists. |\n\n* * *\n\n### **Business Logic Notes**\n\n-   Availability is determined based on **contractor coverage**, **variant eligibility**, and **existing bookings**.\n    \n-   When `provider` is omitted, the API returns aggregate availability across all eligible providers.\n    \n-   If `location.type = \"coordinates\"`, the system automatically determines the coverage area based on geolocation.\n    \n-   Returned dates are always formatted as **ISO 8601** (`YYYY-MM-DD`).\n    \n-   If no available dates are found, an empty array is returned:",
        "tags": [
          "Coverage"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": "{\n    \"location\": { //Required\n        \"type\": \"string\", //\"coordinates\" | \"areaId\" | \"areaReference\",\n        \"value\": \"number | Object\" //number | { lat: number, lng: number }\n    },\n    \"variant\": { //Required\n        \"type\": \"string\", //'variantSku' | 'variantId'\n        \"value\": \"string\"\n    },\n    \"provider\": {\n        \"type\": \"string\", //'providerId' | 'providerReference'\n        \"value\": \"string\"\n    },\n    \"startDate\": \"YYYY-MM-dd\", //Optional, default now()\n    \"quantityOfDays\": \"number\" //Optional, default 5\n}"
            }
          }
        },
        "responses": {
          "400": {
            "description": "InvalidParameters — Missing or invalid request parameters."
          },
          "401": {
            "description": "Missing or expired authentication token."
          },
          "403": {
            "description": "The API key or origin is not authorized to access this resource."
          },
          "404": {
            "description": "The specified variant or provider does not exist or is not linked to the given location."
          },
          "500": {
            "description": "Unexpected server error. Contact support if the issue persists."
          },
          "default": {
            "description": "Available Dates",
            "content": {
              "text/plain": {
                "example": "{\n    \"dates\": [\n        \"2025-01-01\",\n        \"2025-01-02\",\n        \"2025-01-03\",\n    ]\n}"
              }
            }
          }
        }
      }
    },
    "/api/integration/hours/check": {
      "post": {
        "operationId": "coverageAvailableHoursByDate",
        "summary": "Available Hours by Date",
        "description": "### **Purpose**\n\nRetrieves available **time slots** for a given date, based on the requested **location**, **service variant**, and optional **provider** parameters.\n\nDepending on the tenant configuration, the response may return either:\n\n-   A list of **specific times** (in 30-minute intervals), or\n    \n-   A list of **time ranges** (`{ startTime, endTime }`) when time ranges are configured at the tenant level.\n    \n\nThis endpoint allows client systems to display accurate, real-time scheduling options for a specific date.\n\n#### **Field Definitions**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `location` | `object` | ✅ | Defines the geographical reference for checking service availability. |\n| `location.type` | `string` | ✅ | Determines how the location is identified. Accepted values:  \n• `\"coordinates\"` — Uses geographic coordinates.  \n• `\"areaId\"` — Uses the internal Sodtrack area identifier.  \n• `\"areaSku\"` — Uses the SKU associated with a predefined service area. |\n| `location.value` | `object` or `number` or `string` | ✅ | The value corresponding to the selected `location.type`:  \n  \n**If** **`type = \"coordinates\"`** → must be an **object**: `{ \"lat\": number, \"lng\": number }`  \n**If** **`type = \"areaId\"`** → must be a **number** (internal area ID).  \n**If** **`type = \"areaSku\"`** → must be a **string** (area SKU). |\n| `variant` | `object` | ✅ | Identifies the specific service variant for which to check availability. |\n| `variant.type` | `string` | ✅ | Type of variant identifier. Options: `\"variantSku\"` or `\"variantId\"`. |\n| `variant.value` | `string` | ✅ | The SKU or ID of the variant corresponding to the selected `variant.type`. |\n| `provider` | `object` | ❌ | (Optional) Restricts availability to a specific contractor. |\n| `provider.type` | `string` | ❌ | Type of provider identifier. Options: `\"providerId\"` or `\"providerReference\"`. |\n| `provider.value` | `string` | ❌ | The corresponding provider ID or external reference. |\n| `date` | `string` | ✅ | The specific date for which to retrieve available hours. Format: `YYYY-MM-DD`. |\n\n### **Sample Requests**\n\n#### Example 1 — Retrieve hours for coordinates\n\n```\n{\n  \"location\": {\n    \"type\": \"coordinates\",\n    \"value\": { \"lat\": -33.4489, \"lng\": -70.6693 }\n  },\n  \"variant\": {\n    \"type\": \"variantSku\",\n    \"value\": \"install_curtains_sku\"\n  },\n  \"date\": \"2025-10-10\"\n}\n\n```\n\n#### Example 2 — Retrieve hours for a specific provider\n\n```\n{\n  \"location\": {\n    \"type\": \"areaSku\",\n    \"value\": \"SANTIAGO_RM\"\n  },\n  \"variant\": {\n    \"type\": \"variantId\",\n    \"value\": \"567\"\n  },\n  \"provider\": {\n    \"type\": \"providerId\",\n    \"value\": \"999\"\n  },\n  \"date\": \"2025-10-10\"\n}\n\n```\n\n* * *\n\n### **Success Responses (200 OK)**\n\n#### **Example A — Tenant configured for specific times**\n\n```\n{\n  \"hours\": [\n    \"08:00\",\n    \"08:30\",\n    \"09:00\",\n    \"09:30\",\n    \"10:00\"\n  ]\n}\n\n```\n\n#### **Example B — Tenant configured for time ranges**\n\n```\n{\n  \"timeRanges\": [\n    { \"startTime\": \"08:00\", \"endTime\": \"10:00\" },\n    { \"startTime\": \"14:00\", \"endTime\": \"16:30\" }\n  ]\n}\n\n```\n\n#### **Response Fields**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `hours` | `array[string]` | (If applicable) List of available start times in `HH:mm` format, spaced at 30-minute intervals. |\n| `timeRanges` | `array[object]` | (If applicable) List of available time windows. Each object includes:  \n• `startTime`: Start time of the range (`HH:mm`).  \n• `endTime`: End time of the range (`HH:mm`). |\n\n**Note:** The API will return **either** **`hours`** **or** **`timeRanges`**, depending on tenant configuration.\n\n* * *\n\n### **Error Responses**\n\n| HTTP Status | Error Code / Key | Description |\n| --- | --- | --- |\n| `400 Bad Request` | `InvalidParameters` | Missing or invalid request parameters. |\n| `401 Unauthorized` | — | Authentication failed or token expired. |\n| `403 Forbidden` | — | The API key or origin is not authorized to access this endpoint. |\n| `404 Not Found` | — | No availability found for the given date or parameters. |\n| `500 Internal Server Error` | — | Unexpected server-side error. Contact Sodtrack support. |\n\n* * *\n\n### **Business Logic Notes**\n\n-   Availability is derived from contractor schedules, coverage zones, and existing bookings.\n    \n-   When the tenant is configured for **time ranges**, returned windows are inclusive and may vary in length (e.g., 2-hour blocks).\n    \n-   When configured for **specific times**, availability is expressed in **30-minute intervals**.\n    \n-   { \"hours\": \\[\\] }{ \"timeRanges\": \\[\\] }\n    \n    or\n    \n-   All times are expressed in **local time** relative to the contractor’s region or the defined coverage area.",
        "tags": [
          "Coverage"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": "{\n    \"location\": { //Required\n        \"type\": \"string\", //\"coordinates\" | \"areaId\" | \"areaReference\",\n        \"value\": \"number | Object\" //number | { lat: number, lng: number }\n    },\n    \"variant\": { //Required\n        \"type\": \"string\", //'variantSku' | 'variantId'\n        \"value\": \"string\"\n    },\n    \"provider\": {\n        \"type\": \"string\", //'providerId' | 'providerReference'\n        \"value\": \"string\"\n    },\n    \"date\": \"YYYY-MM-dd\" //Required\n}"
            }
          }
        },
        "responses": {
          "400": {
            "description": "InvalidParameters — Missing or invalid request parameters."
          },
          "401": {
            "description": "Authentication failed or token expired."
          },
          "403": {
            "description": "The API key or origin is not authorized to access this endpoint."
          },
          "404": {
            "description": "No availability found for the given date or parameters."
          },
          "500": {
            "description": "Unexpected server-side error. Contact Sodtrack support."
          },
          "default": {
            "description": "Available Hours by Date",
            "content": {
              "text/plain": {
                "example": {
                  "timeRanges": [
                    {
                      "startTime": "08:00",
                      "endTime": "10:00"
                    },
                    {
                      "startTime": "14:00",
                      "endTime": "16:30"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "BookingDoneEvent": {
      "post": {
        "operationId": "webhookBookingdoneevent",
        "summary": "BookingDoneEvent",
        "description": "### **Purpose**\n\nThe `BookingDoneEvent` webhook notifies subscribers when a **booking has been successfully completed** within the Sodtrack platform.\n\nThis event is triggered once a booking’s lifecycle reaches the **“done”** status — typically after the assigned technician or provider has finalized the job, submitted the completion report, or confirmed the service outcome.\n\nIntegrating this webhook allows client systems to automatically synchronize booking statuses, trigger post-service workflows (e.g., invoicing, customer feedback collection, or ERP updates), and maintain real-time operational consistency with Sodtrack.\n\n* * *\n\n### **Trigger Condition**\n\nThis webhook is triggered when:\n\n-   A booking’s status transitions to `\"done\"`\n    \n-   The booking completion is successfully recorded in the Sodtrack system.\n    \n\nOnly bookings that have been fully processed and validated by the system generate this event.\n\n* * *\n\n### **Example Use Cases**\n\n-   Automatically update booking statuses in external CRMs, ERPs, or scheduling systems.\n    \n-   Trigger post-completion workflows such as invoice generation, customer satisfaction surveys, or performance analytics.\n    \n-   Maintain synchronized service completion records between Sodtrack and third-party platforms.\n    \n\n* * *\n\n#### **Body**\n\nThe body of this webhook inherits the standard Sodtrack webhook structure, which includes:\n\n-   The common [shared webhook fields](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-26cff07c-8b16-4266-a0b1-6f273d6ea321?action=share&creator=30960189)\n    \n-   The [booking objects](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-e6cafcc6-8fb9-40ab-b166-467702ad3948?action=share&creator=30960189)\n    \n\n#### Event-Specific Fields\n\nIn addition to the [shared webhook fields](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-26cff07c-8b16-4266-a0b1-6f273d6ea321?action=share&creator=30960189) and the standard [booking](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-e6cafcc6-8fb9-40ab-b166-467702ad3948?action=share&creator=30960189) object, this event includes the following additional field:\n\n| Field | Type | Description | Always |\n| --- | --- | --- | --- |\n| `forced` | boolean | Indicates whether the booking was forcefully marked as completed. | ✅ |",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "timestamp": {
                    "type": "string"
                  },
                  "userTriggererEmail": {
                    "type": "string"
                  },
                  "forced": {
                    "type": "string"
                  },
                  "booking": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "createdDate": {
                        "type": "string"
                      },
                      "serviceVariantTotalPrice": {
                        "type": "string"
                      },
                      "serviceVariantTotalCost": {
                        "type": "string"
                      },
                      "serviceName": {
                        "type": "string"
                      },
                      "totalAddonsCost": {
                        "type": "string"
                      },
                      "totalAddonsPrice": {
                        "type": "string"
                      },
                      "totalAddonsDuration": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "variantDuration": {
                        "type": "string"
                      },
                      "transportCost": {
                        "type": "string"
                      },
                      "quantity": {
                        "type": "string"
                      },
                      "date": {
                        "type": "string"
                      },
                      "doneDate": {
                        "type": "string"
                      },
                      "periodStartTime": {
                        "type": "string"
                      },
                      "periodEndTime": {
                        "type": "string"
                      },
                      "finalCost": {
                        "type": "string"
                      },
                      "finalPrice": {
                        "type": "string"
                      },
                      "totalDuration": {
                        "type": "string"
                      },
                      "category": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "saleChannel": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "shoppingCartId": {
                        "type": "string"
                      },
                      "serviceVariant": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "skus": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "addons": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "duration": {
                              "type": "string"
                            },
                            "totalCost": {
                              "type": "string"
                            },
                            "totalPrice": {
                              "type": "string"
                            },
                            "unitCost": {
                              "type": "string"
                            },
                            "unitPrice": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "productPromisedDeliveryDate": {
                              "type": "string"
                            },
                            "sku": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "price": {
                              "type": "string"
                            },
                            "unit": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "serialNumber": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "dynamicFieldValues": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "dynamicFormFields": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reference": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "identificationNumber": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "coordinates": {
                        "type": "object",
                        "properties": {
                          "lng": {
                            "type": "string"
                          },
                          "lat": {
                            "type": "string"
                          }
                        }
                      },
                      "address": {
                        "type": "string"
                      },
                      "formattedAddress": {
                        "type": "string"
                      },
                      "areas": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "reference": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "professional": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "isCompany": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "timestamp": "string",
                "userTriggererEmail": "string",
                "forced": "boolean",
                "booking": {
                  "id": "number",
                  "reference": "string",
                  "createdDate": "Date",
                  "serviceVariantTotalPrice": "number",
                  "serviceVariantTotalCost": "number",
                  "serviceName": "string",
                  "totalAddonsCost": "number",
                  "totalAddonsPrice": "number",
                  "totalAddonsDuration": "number",
                  "status": "string",
                  "variantDuration": "number",
                  "transportCost": "number",
                  "quantity": "number",
                  "date": "Date",
                  "doneDate": "Date",
                  "periodStartTime": "Date",
                  "periodEndTime": "Date",
                  "finalCost": "number",
                  "finalPrice": "number",
                  "totalDuration": "number",
                  "category": {
                    "id": "number",
                    "name": "string"
                  },
                  "saleChannel": {
                    "id": "number",
                    "name": "string"
                  },
                  "shoppingCartId": "number",
                  "serviceVariant": {
                    "id": "number",
                    "name": "string",
                    "skus": [
                      {
                        "id": "number",
                        "sku": "string"
                      }
                    ]
                  },
                  "addons": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "name": "string",
                      "duration": "number",
                      "totalCost": "number",
                      "totalPrice": "number",
                      "unitCost": "number",
                      "unitPrice": "number"
                    }
                  ],
                  "products": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "productPromisedDeliveryDate": "Date",
                      "sku": "string",
                      "name": "string",
                      "description": "string",
                      "price": "number",
                      "unit": {
                        "id": "number",
                        "serialNumber": "string"
                      }
                    }
                  ],
                  "dynamicFieldValues": [
                    {
                      "id": "number",
                      "value": "string"
                    }
                  ],
                  "dynamicFormFields": [
                    {
                      "reference": "string",
                      "value": "string"
                    }
                  ]
                },
                "customer": {
                  "id": "number",
                  "name": "string",
                  "identificationNumber": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                },
                "address": {
                  "id": "number",
                  "coordinates": {
                    "lng": "number",
                    "lat": "number"
                  },
                  "address": "string",
                  "formattedAddress": "string",
                  "areas": [
                    {
                      "id": "number",
                      "name": "string",
                      "reference": ""
                    }
                  ]
                },
                "professional": {
                  "id": "number",
                  "isCompany": "boolean",
                  "reference": "string",
                  "name": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    },
    "BookingAcceptedEvent": {
      "post": {
        "operationId": "webhookBookingacceptedevent",
        "summary": "BookingAcceptedEvent",
        "description": "### **Purpose**\n\nThe `BookingAcceptedEvent` webhook notifies subscribers when a booking has been accepted by a service provider within the Sodtrack platform.\n\nThis event is triggered when a provider confirms their availability and commitment to fulfill a service request — typically when a technician or professional accepts a booking assignment with a scheduled date, when a booking with an assigned provider is scheduled by the customer, or a provider and date is assigned directly.\n\nThe booking transitions to **\"accepted\"** status, indicating that a provider is committed to delivering the service at a specific date and time.\n\nIntegrating this webhook allows client systems to automatically track provider confirmations, trigger post-acceptance workflows (e.g., customer notifications, schedule confirmations, resource preparation, calendar updates), and maintain real-time operational consistency with Sodtrack.\n\n* * *\n\n### **Trigger Condition**\n\nThis webhook is triggered when:\n\n-   The booking has an assigned provider.\n    \n-   The booking has a scheduled date and time assigned.\n    \n-   The booking status transitions to **\"accepted\"** in the Sodtrack system.\n    \n\n* * *\n\n### **Example Use Cases**\n\n-   Automatically send confirmation notifications to customers when a provider accepts their booking with a scheduled date.\n    \n-   Synchronize provider acceptance records with external workforce management or scheduling systems.\n    \n-   Trigger preparation workflows such as resource allocation, equipment assignment, or route optimization.\n    \n-   Update calendar systems with confirmed appointments for both customers and providers.\n    \n-   Track provider performance metrics based on acceptance patterns and response times.\n    \n-   Maintain synchronized booking status records between Sodtrack and third-party platforms.\n    \n\n* * *\n\n#### **Body**\n\nThe body of this webhook inherits the standard Sodtrack webhook structure, which includes:\n\n-   The common [shared webhook fields](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-26cff07c-8b16-4266-a0b1-6f273d6ea321?action=share&creator=30960189)\n    \n-   The [booking objects](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-e6cafcc6-8fb9-40ab-b166-467702ad3948?action=share&creator=30960189)",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "timestamp": {
                    "type": "string"
                  },
                  "userTriggererEmail": {
                    "type": "string"
                  },
                  "booking": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "createdDate": {
                        "type": "string"
                      },
                      "serviceVariantTotalPrice": {
                        "type": "string"
                      },
                      "serviceVariantTotalCost": {
                        "type": "string"
                      },
                      "serviceName": {
                        "type": "string"
                      },
                      "totalAddonsCost": {
                        "type": "string"
                      },
                      "totalAddonsPrice": {
                        "type": "string"
                      },
                      "totalAddonsDuration": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "variantDuration": {
                        "type": "string"
                      },
                      "transportCost": {
                        "type": "string"
                      },
                      "quantity": {
                        "type": "string"
                      },
                      "date": {
                        "type": "string"
                      },
                      "doneDate": {
                        "type": "string"
                      },
                      "periodStartTime": {
                        "type": "string"
                      },
                      "periodEndTime": {
                        "type": "string"
                      },
                      "finalCost": {
                        "type": "string"
                      },
                      "finalPrice": {
                        "type": "string"
                      },
                      "totalDuration": {
                        "type": "string"
                      },
                      "category": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "saleChannel": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "shoppingCartId": {
                        "type": "string"
                      },
                      "serviceVariant": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "skus": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "addons": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "duration": {
                              "type": "string"
                            },
                            "totalCost": {
                              "type": "string"
                            },
                            "totalPrice": {
                              "type": "string"
                            },
                            "unitCost": {
                              "type": "string"
                            },
                            "unitPrice": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "productPromisedDeliveryDate": {
                              "type": "string"
                            },
                            "sku": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "price": {
                              "type": "string"
                            },
                            "unit": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "serialNumber": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "dynamicFieldValues": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "dynamicFormFields": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reference": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "identificationNumber": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "coordinates": {
                        "type": "object",
                        "properties": {
                          "lng": {
                            "type": "string"
                          },
                          "lat": {
                            "type": "string"
                          }
                        }
                      },
                      "address": {
                        "type": "string"
                      },
                      "formattedAddress": {
                        "type": "string"
                      },
                      "areas": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "reference": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "professional": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "isCompany": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "timestamp": "string",
                "userTriggererEmail": "string",
                "booking": {
                  "id": "number",
                  "reference": "string",
                  "createdDate": "Date",
                  "serviceVariantTotalPrice": "number",
                  "serviceVariantTotalCost": "number",
                  "serviceName": "string",
                  "totalAddonsCost": "number",
                  "totalAddonsPrice": "number",
                  "totalAddonsDuration": "number",
                  "status": "string",
                  "variantDuration": "number",
                  "transportCost": "number",
                  "quantity": "number",
                  "date": "Date",
                  "doneDate": "Date",
                  "periodStartTime": "Date",
                  "periodEndTime": "Date",
                  "finalCost": "number",
                  "finalPrice": "number",
                  "totalDuration": "number",
                  "category": {
                    "id": "number",
                    "name": "string"
                  },
                  "saleChannel": {
                    "id": "number",
                    "name": "string"
                  },
                  "shoppingCartId": "number",
                  "serviceVariant": {
                    "id": "number",
                    "name": "string",
                    "skus": [
                      {
                        "id": "number",
                        "sku": "string"
                      }
                    ]
                  },
                  "addons": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "name": "string",
                      "duration": "number",
                      "totalCost": "number",
                      "totalPrice": "number",
                      "unitCost": "number",
                      "unitPrice": "number"
                    }
                  ],
                  "products": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "productPromisedDeliveryDate": "Date",
                      "sku": "string",
                      "name": "string",
                      "description": "string",
                      "price": "number",
                      "unit": {
                        "id": "number",
                        "serialNumber": "string"
                      }
                    }
                  ],
                  "dynamicFieldValues": [
                    {
                      "id": "number",
                      "value": "string"
                    }
                  ],
                  "dynamicFormFields": [
                    {
                      "reference": "string",
                      "value": "string"
                    }
                  ]
                },
                "customer": {
                  "id": "number",
                  "name": "string",
                  "identificationNumber": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                },
                "address": {
                  "id": "number",
                  "coordinates": {
                    "lng": "number",
                    "lat": "number"
                  },
                  "address": "string",
                  "formattedAddress": "string",
                  "areas": [
                    {
                      "id": "number",
                      "name": "string",
                      "reference": ""
                    }
                  ]
                },
                "professional": {
                  "id": "number",
                  "isCompany": "boolean",
                  "reference": "string",
                  "name": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    },
    "BookingCreatedEvent": {
      "post": {
        "operationId": "webhookBookingcreatedevent",
        "summary": "BookingCreatedEvent",
        "description": "### **Purpose**\n\nThe `BookingCreatedEvent` webhook notifies subscribers when a **new booking has been successfully created** within the Sodtrack platform.\n\nThis event is triggered once a booking is created and initialized in the system — typically after a customer completes a service request, a booking is generated from a shopping cart, or a booking is created from a budget execution. At this point, the booking enters the **“created”** status and becomes ready for provider assignment and scheduling.\n\nIntegrating this webhook allows client systems to automatically synchronize new booking records, trigger initial workflows (e.g., provider matching, resource allocation, or external system notifications), and maintain real-time operational consistency with Sodtrack.\n\n* * *\n\n### **Trigger Condition**\n\nThis webhook is triggered when:\n\n-   A new booking is successfully created in the Sodtrack system, and\n    \n-   The booking has been initialized with all required information and assigned the `\"created\"` status.\n    \n\nOnly bookings that have been fully validated and persisted by the system generate this event.\n\n* * *\n\n### **Example Use Cases**\n\n-   Automatically synchronize new booking records in external CRMs, ERPs, or scheduling systems.\n    \n-   Maintain synchronized booking creation records between Sodtrack and third-party platforms.\n    \n-   Initiate notification workflows to stakeholders about new service requests.\n    \n\n* * *\n\n#### **Body**\n\nThe body of this webhook inherits the standard Sodtrack webhook structure, which includes:\n\n-   The common [shared webhook fields](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-26cff07c-8b16-4266-a0b1-6f273d6ea321?action=share&creator=30960189)\n    \n-   The [booking objects](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-e6cafcc6-8fb9-40ab-b166-467702ad3948?action=share&creator=30960189)",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "timestamp": {
                    "type": "string"
                  },
                  "userTriggererEmail": {
                    "type": "string"
                  },
                  "booking": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "createdDate": {
                        "type": "string"
                      },
                      "serviceVariantTotalPrice": {
                        "type": "string"
                      },
                      "serviceVariantTotalCost": {
                        "type": "string"
                      },
                      "serviceName": {
                        "type": "string"
                      },
                      "totalAddonsCost": {
                        "type": "string"
                      },
                      "totalAddonsPrice": {
                        "type": "string"
                      },
                      "totalAddonsDuration": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "variantDuration": {
                        "type": "string"
                      },
                      "transportCost": {
                        "type": "string"
                      },
                      "quantity": {
                        "type": "string"
                      },
                      "date": {
                        "type": "string"
                      },
                      "doneDate": {
                        "type": "string"
                      },
                      "periodStartTime": {
                        "type": "string"
                      },
                      "periodEndTime": {
                        "type": "string"
                      },
                      "finalCost": {
                        "type": "string"
                      },
                      "finalPrice": {
                        "type": "string"
                      },
                      "totalDuration": {
                        "type": "string"
                      },
                      "category": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "saleChannel": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "shoppingCartId": {
                        "type": "string"
                      },
                      "serviceVariant": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "skus": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "addons": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "duration": {
                              "type": "string"
                            },
                            "totalCost": {
                              "type": "string"
                            },
                            "totalPrice": {
                              "type": "string"
                            },
                            "unitCost": {
                              "type": "string"
                            },
                            "unitPrice": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "productPromisedDeliveryDate": {
                              "type": "string"
                            },
                            "sku": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "price": {
                              "type": "string"
                            },
                            "unit": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "serialNumber": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "dynamicFieldValues": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "dynamicFormFields": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reference": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "identificationNumber": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "coordinates": {
                        "type": "object",
                        "properties": {
                          "lng": {
                            "type": "string"
                          },
                          "lat": {
                            "type": "string"
                          }
                        }
                      },
                      "address": {
                        "type": "string"
                      },
                      "formattedAddress": {
                        "type": "string"
                      },
                      "areas": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "reference": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "professional": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "isCompany": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "timestamp": "string",
                "userTriggererEmail": "string",
                "booking": {
                  "id": "number",
                  "reference": "string",
                  "createdDate": "Date",
                  "serviceVariantTotalPrice": "number",
                  "serviceVariantTotalCost": "number",
                  "serviceName": "string",
                  "totalAddonsCost": "number",
                  "totalAddonsPrice": "number",
                  "totalAddonsDuration": "number",
                  "status": "string",
                  "variantDuration": "number",
                  "transportCost": "number",
                  "quantity": "number",
                  "date": "Date",
                  "doneDate": "Date",
                  "periodStartTime": "Date",
                  "periodEndTime": "Date",
                  "finalCost": "number",
                  "finalPrice": "number",
                  "totalDuration": "number",
                  "category": {
                    "id": "number",
                    "name": "string"
                  },
                  "saleChannel": {
                    "id": "number",
                    "name": "string"
                  },
                  "shoppingCartId": "number",
                  "serviceVariant": {
                    "id": "number",
                    "name": "string",
                    "skus": [
                      {
                        "id": "number",
                        "sku": "string"
                      }
                    ]
                  },
                  "addons": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "name": "string",
                      "duration": "number",
                      "totalCost": "number",
                      "totalPrice": "number",
                      "unitCost": "number",
                      "unitPrice": "number"
                    }
                  ],
                  "products": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "productPromisedDeliveryDate": "Date",
                      "sku": "string",
                      "name": "string",
                      "description": "string",
                      "price": "number",
                      "unit": {
                        "id": "number",
                        "serialNumber": "string"
                      }
                    }
                  ],
                  "dynamicFieldValues": [
                    {
                      "id": "number",
                      "value": "string"
                    }
                  ],
                  "dynamicFormFields": [
                    {
                      "reference": "string",
                      "value": "string"
                    }
                  ]
                },
                "customer": {
                  "id": "number",
                  "name": "string",
                  "identificationNumber": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                },
                "address": {
                  "id": "number",
                  "coordinates": {
                    "lng": "number",
                    "lat": "number"
                  },
                  "address": "string",
                  "formattedAddress": "string",
                  "areas": [
                    {
                      "id": "number",
                      "name": "string",
                      "reference": ""
                    }
                  ]
                },
                "professional": {
                  "id": "number",
                  "isCompany": "boolean",
                  "reference": "string",
                  "name": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    },
    "BookingProviderAssignedEvent": {
      "post": {
        "operationId": "webhookBookingproviderassignedevent",
        "summary": "BookingProviderAssignedEvent",
        "description": "### **Purpose**\n\nThe `BookingProviderAssignedEvent` webhook notifies subscribers when a **service provider** (technician, professional, or company) has been **assigned to a booking** within the Sodtrack platform.\n\nThis event is triggered when a provider is matched and assigned to fulfill a service request — typically through **automatic matching algorithms**, **manual assignment by administrators**, or when a **provider accepts a booking request**.\n\nIntegrating this webhook allows client systems to automatically track provider assignments, trigger provider-specific workflows (e.g., job notifications, schedule synchronization, resource preparation), handle provider reassignments, and maintain real-time operational consistency with Sodtrack.\n\n* * *\n\n### **Trigger Condition**\n\nThis webhook is triggered when:\n\n-   A provider is successfully assigned to a booking (either initial assignment or reassignment), and\n    \n-   The provider assignment is recorded and validated in the Sodtrack system.\n    \n\nThe event includes information about the assigned provider and the booking details, enabling systems to handle provider assignments appropriately.\n\n* * *\n\n### **Example Use Cases**\n\n-   Automatically synchronize provider assignments in external workforce management, ERP, or scheduling systems.\n    \n-   Trigger provider notification workflows (e.g., job alerts, schedule updates, mobile app notifications).\n    \n-   Maintain synchronized provider assignment records between Sodtrack and third-party platforms.\n    \n-   Handle provider reassignment logic, including notification of previous providers when assignments change.\n    \n-   Update resource allocation and capacity planning systems based on provider commitments.\n    \n-   Track provider performance metrics by monitoring assignment frequency and patterns.\n    \n\n* * *\n\n#### **Body**\n\nThe body of this webhook inherits the standard Sodtrack webhook structure, which includes:\n\n-   The common [shared webhook fields](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-26cff07c-8b16-4266-a0b1-6f273d6ea321?action=share&creator=30960189)\n    \n-   The [booking objects](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-e6cafcc6-8fb9-40ab-b166-467702ad3948?action=share&creator=30960189)",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "timestamp": {
                    "type": "string"
                  },
                  "userTriggererEmail": {
                    "type": "string"
                  },
                  "booking": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "createdDate": {
                        "type": "string"
                      },
                      "serviceVariantTotalPrice": {
                        "type": "string"
                      },
                      "serviceVariantTotalCost": {
                        "type": "string"
                      },
                      "serviceName": {
                        "type": "string"
                      },
                      "totalAddonsCost": {
                        "type": "string"
                      },
                      "totalAddonsPrice": {
                        "type": "string"
                      },
                      "totalAddonsDuration": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "variantDuration": {
                        "type": "string"
                      },
                      "transportCost": {
                        "type": "string"
                      },
                      "quantity": {
                        "type": "string"
                      },
                      "date": {
                        "type": "string"
                      },
                      "doneDate": {
                        "type": "string"
                      },
                      "periodStartTime": {
                        "type": "string"
                      },
                      "periodEndTime": {
                        "type": "string"
                      },
                      "finalCost": {
                        "type": "string"
                      },
                      "finalPrice": {
                        "type": "string"
                      },
                      "totalDuration": {
                        "type": "string"
                      },
                      "category": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "saleChannel": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "shoppingCartId": {
                        "type": "string"
                      },
                      "serviceVariant": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "skus": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "addons": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "duration": {
                              "type": "string"
                            },
                            "totalCost": {
                              "type": "string"
                            },
                            "totalPrice": {
                              "type": "string"
                            },
                            "unitCost": {
                              "type": "string"
                            },
                            "unitPrice": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "productPromisedDeliveryDate": {
                              "type": "string"
                            },
                            "sku": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "price": {
                              "type": "string"
                            },
                            "unit": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "serialNumber": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "dynamicFieldValues": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "dynamicFormFields": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reference": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "identificationNumber": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "coordinates": {
                        "type": "object",
                        "properties": {
                          "lng": {
                            "type": "string"
                          },
                          "lat": {
                            "type": "string"
                          }
                        }
                      },
                      "address": {
                        "type": "string"
                      },
                      "formattedAddress": {
                        "type": "string"
                      },
                      "areas": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "reference": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "professional": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "isCompany": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "timestamp": "string",
                "userTriggererEmail": "string",
                "booking": {
                  "id": "number",
                  "reference": "string",
                  "createdDate": "Date",
                  "serviceVariantTotalPrice": "number",
                  "serviceVariantTotalCost": "number",
                  "serviceName": "string",
                  "totalAddonsCost": "number",
                  "totalAddonsPrice": "number",
                  "totalAddonsDuration": "number",
                  "status": "string",
                  "variantDuration": "number",
                  "transportCost": "number",
                  "quantity": "number",
                  "date": "Date",
                  "doneDate": "Date",
                  "periodStartTime": "Date",
                  "periodEndTime": "Date",
                  "finalCost": "number",
                  "finalPrice": "number",
                  "totalDuration": "number",
                  "category": {
                    "id": "number",
                    "name": "string"
                  },
                  "saleChannel": {
                    "id": "number",
                    "name": "string"
                  },
                  "shoppingCartId": "number",
                  "serviceVariant": {
                    "id": "number",
                    "name": "string",
                    "skus": [
                      {
                        "id": "number",
                        "sku": "string"
                      }
                    ]
                  },
                  "addons": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "name": "string",
                      "duration": "number",
                      "totalCost": "number",
                      "totalPrice": "number",
                      "unitCost": "number",
                      "unitPrice": "number"
                    }
                  ],
                  "products": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "productPromisedDeliveryDate": "Date",
                      "sku": "string",
                      "name": "string",
                      "description": "string",
                      "price": "number",
                      "unit": {
                        "id": "number",
                        "serialNumber": "string"
                      }
                    }
                  ],
                  "dynamicFieldValues": [
                    {
                      "id": "number",
                      "value": "string"
                    }
                  ],
                  "dynamicFormFields": [
                    {
                      "reference": "string",
                      "value": "string"
                    }
                  ]
                },
                "customer": {
                  "id": "number",
                  "name": "string",
                  "identificationNumber": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                },
                "address": {
                  "id": "number",
                  "coordinates": {
                    "lng": "number",
                    "lat": "number"
                  },
                  "address": "string",
                  "formattedAddress": "string",
                  "areas": [
                    {
                      "id": "number",
                      "name": "string",
                      "reference": ""
                    }
                  ]
                },
                "professional": {
                  "id": "number",
                  "isCompany": "boolean",
                  "reference": "string",
                  "name": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    },
    "BookingCancelledEvent": {
      "post": {
        "operationId": "webhookBookingcancelledevent",
        "summary": "BookingCancelledEvent",
        "description": "### **Purpose**\n\nThe `BookingCancelledEvent` webhook notifies subscribers when a **booking has been cancelled** within the Sodtrack platform.\n\nThis event is triggered when a booking's lifecycle is **terminated before completion** — typically when a customer cancels the service request, an administrator cancels the booking, or the booking is cancelled due to an incident resolution.  \nOnce triggered, the booking transitions to the **“cancelled”** status and ceases active processing.\n\nIntegrating this webhook allows client systems to automatically synchronize booking cancellations, trigger post-cancellation workflows (e.g., refund processing, resource reallocation, inventory updates, or customer communication), and maintain real-time operational consistency with Sodtrack.\n\n* * *\n\n### **Trigger Condition**\n\nThis webhook is triggered when:\n\n-   A booking's status transitions to `\"cancelled\"`, and\n    \n-   The booking cancellation is successfully recorded in the Sodtrack system.\n    \n\nOnly bookings that have been properly cancelled and validated by the system generate this event.\n\n* * *\n\n### **Example Use Cases**\n\n-   Automatically update booking statuses in external CRMs, ERPs, or scheduling systems to reflect cancellations.\n    \n-   Trigger post-cancellation workflows such as refund processing, provider compensation calculations, or resource reallocation.\n    \n-   Maintain synchronized cancellation records between Sodtrack and third-party platforms.\n    \n-   Initiate customer communication workflows (e.g., cancellation confirmations, feedback requests).\n    \n-   Update inventory and availability management systems to free up previously allocated resources.\n    \n\n* * *\n\n#### **Body**\n\nThe body of this webhook inherits the standard Sodtrack webhook structure, which includes:\n\n-   The common [shared webhook fields](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-26cff07c-8b16-4266-a0b1-6f273d6ea321?action=share&creator=30960189)\n    \n-   The [booking objects](https://sodtrack.postman.co/workspace/Sodtrack-Dev~5ddbf68f-e739-422b-852a-e24bb8fc6417/folder/30960189-e6cafcc6-8fb9-40ab-b166-467702ad3948?action=share&creator=30960189)",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "timestamp": {
                    "type": "string"
                  },
                  "userTriggererEmail": {
                    "type": "string"
                  },
                  "booking": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "createdDate": {
                        "type": "string"
                      },
                      "serviceVariantTotalPrice": {
                        "type": "string"
                      },
                      "serviceVariantTotalCost": {
                        "type": "string"
                      },
                      "serviceName": {
                        "type": "string"
                      },
                      "totalAddonsCost": {
                        "type": "string"
                      },
                      "totalAddonsPrice": {
                        "type": "string"
                      },
                      "totalAddonsDuration": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "variantDuration": {
                        "type": "string"
                      },
                      "transportCost": {
                        "type": "string"
                      },
                      "quantity": {
                        "type": "string"
                      },
                      "date": {
                        "type": "string"
                      },
                      "doneDate": {
                        "type": "string"
                      },
                      "periodStartTime": {
                        "type": "string"
                      },
                      "periodEndTime": {
                        "type": "string"
                      },
                      "finalCost": {
                        "type": "string"
                      },
                      "finalPrice": {
                        "type": "string"
                      },
                      "totalDuration": {
                        "type": "string"
                      },
                      "category": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "saleChannel": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "shoppingCartId": {
                        "type": "string"
                      },
                      "serviceVariant": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "skus": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "addons": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "duration": {
                              "type": "string"
                            },
                            "totalCost": {
                              "type": "string"
                            },
                            "totalPrice": {
                              "type": "string"
                            },
                            "unitCost": {
                              "type": "string"
                            },
                            "unitPrice": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "string"
                            },
                            "productPromisedDeliveryDate": {
                              "type": "string"
                            },
                            "sku": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "price": {
                              "type": "string"
                            },
                            "unit": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "serialNumber": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "dynamicFieldValues": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "dynamicFormFields": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reference": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "identificationNumber": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "coordinates": {
                        "type": "object",
                        "properties": {
                          "lng": {
                            "type": "string"
                          },
                          "lat": {
                            "type": "string"
                          }
                        }
                      },
                      "address": {
                        "type": "string"
                      },
                      "formattedAddress": {
                        "type": "string"
                      },
                      "areas": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "reference": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  },
                  "professional": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "isCompany": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phoneNumber": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "timestamp": "string",
                "userTriggererEmail": "string",
                "booking": {
                  "id": "number",
                  "reference": "string",
                  "createdDate": "Date",
                  "serviceVariantTotalPrice": "number",
                  "serviceVariantTotalCost": "number",
                  "serviceName": "string",
                  "totalAddonsCost": "number",
                  "totalAddonsPrice": "number",
                  "totalAddonsDuration": "number",
                  "status": "string",
                  "variantDuration": "number",
                  "transportCost": "number",
                  "quantity": "number",
                  "date": "Date",
                  "doneDate": "Date",
                  "periodStartTime": "Date",
                  "periodEndTime": "Date",
                  "finalCost": "number",
                  "finalPrice": "number",
                  "totalDuration": "number",
                  "category": {
                    "id": "number",
                    "name": "string"
                  },
                  "saleChannel": {
                    "id": "number",
                    "name": "string"
                  },
                  "shoppingCartId": "number",
                  "serviceVariant": {
                    "id": "number",
                    "name": "string",
                    "skus": [
                      {
                        "id": "number",
                        "sku": "string"
                      }
                    ]
                  },
                  "addons": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "name": "string",
                      "duration": "number",
                      "totalCost": "number",
                      "totalPrice": "number",
                      "unitCost": "number",
                      "unitPrice": "number"
                    }
                  ],
                  "products": [
                    {
                      "id": "number",
                      "quantity": "number",
                      "productPromisedDeliveryDate": "Date",
                      "sku": "string",
                      "name": "string",
                      "description": "string",
                      "price": "number",
                      "unit": {
                        "id": "number",
                        "serialNumber": "string"
                      }
                    }
                  ],
                  "dynamicFieldValues": [
                    {
                      "id": "number",
                      "value": "string"
                    }
                  ],
                  "dynamicFormFields": [
                    {
                      "reference": "string",
                      "value": "string"
                    }
                  ]
                },
                "customer": {
                  "id": "number",
                  "name": "string",
                  "identificationNumber": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                },
                "address": {
                  "id": "number",
                  "coordinates": {
                    "lng": "number",
                    "lat": "number"
                  },
                  "address": "string",
                  "formattedAddress": "string",
                  "areas": [
                    {
                      "id": "number",
                      "name": "string",
                      "reference": ""
                    }
                  ]
                },
                "professional": {
                  "id": "number",
                  "isCompany": "boolean",
                  "reference": "string",
                  "name": "string",
                  "lastName": "string",
                  "email": "string",
                  "phoneNumber": "string"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    },
    "BudgetExecutionStatusChangedToWaitingForCustomerApprovalEvent": {
      "post": {
        "operationId": "webhookBudgetexecutionstatuschangedtowaitingforcustomerapprovaleven",
        "summary": "BudgetExecutionStatusChangedToWaitingForCustomerApprovalEvent",
        "description": "### **Purpose**\n\nSodtrack sends this payload when a budget execution changes to **waiting for customer approval**, meaning the budget has been prepared and is now published to the customer for review, approval or rejection.\n\nThe payload describes **what is being quoted** (`quote`) and **who the budget is for** (`context`). It is a complete snapshot at the moment of submission: every line item, labor activity, discount, surcharge, customer-facing attachment and the full amount breakdown are included, so the receiving system can reproduce the quote without any additional call to Sodtrack.\n\nThe payload has the same shape for budgets created from an existing booking and for standalone budgets. Use `context.hasOriginBooking` to tell the two apart.\n\n* * *\n\n### **Field Definitions**\n\n#### 🧾 **Quote**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `quote.type` | \\`string | null\\` |\n| `quote.description` | \\`string | null\\` |\n| `quote.items` | `array` | Priced materials, products and components. Empty when the budget is not itemized. |\n| `quote.activities` | `array` | Priced labor activities. Empty when the budget is not itemized. |\n| `quote.discounts` | `array` | Discounts applied to the budget. Empty when none. |\n| `quote.surcharges` | `array` | Surcharges applied to the budget. Empty when none. |\n| `quote.attachments` | `array` | Attachments explicitly shared with the customer. Empty when none. |\n| `quote.totals` | `object` | Full amount breakdown. Always present. |\n\n* * *\n\n#### 📦 **Quote items** — `quote.items[]`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier for the line. |\n| `name` | \\`string | null\\` |\n| `description` | \\`string | null\\` |\n| `sku` | \\`string | null\\` |\n| `type` | `string` | One of: `\"material\"`, `\"product\"`, `\"component\"`. |\n| `costType` | `string` | How the line is priced. One of: `\"metric\"` (unit price × quantity), `\"total\"` (flat amount). |\n| `quantity` | \\`number | null\\` |\n| `metric` | \\`string | null\\` |\n| `metricCost` | \\`number | null\\` |\n| `totalCost` | \\`number | null\\` |\n| `lineTotal` | `number` | Amount contributed by this line, already resolved for both pricing models. |\n| `required` | `boolean` | Whether the line is mandatory in the budget. |\n\nUse `lineTotal` rather than recomputing from `quantity` and `metricCost`: it is calculated by Sodtrack with the same rules used for the totals.\n\n* * *\n\n#### 👷 **Quote activities** — `quote.activities[]`\n\nLabor performed as part of the budget.\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier for the activity. |\n| `name` | `string` | Activity name. |\n| `description` | \\`string | null\\` |\n| `order` | \\`number | null\\` |\n| `quantity` | \\`number | null\\` |\n| `metric` | \\`string | null\\` |\n| `costPerMetric` | \\`number | null\\` |\n| `typeCost` | \\`string | null\\` |\n| `globalCost` | \\`number | null\\` |\n| `lineTotal` | `number` | Amount contributed by this activity. |\n| `required` | \\`boolean | null\\` |\n| `products` | `array` | Materials consumed by the activity. Empty when none. |\n\n* * *\n\n#### 🧰 **Activity products** — `quote.activities[].products[]`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier. |\n| `name` | `string` | Product name. |\n| `description` | \\`string | null\\` |\n| `quantity` | \\`number | null\\` |\n| `productMetric` | \\`string | null\\` |\n| `productMetricCost` | \\`number | null\\` |\n| `lineTotal` | `number` | `quantity × productMetricCost`. |\n\n⚠️ Activity products are **informational**. They do not contribute to `quote.totals` in itemized or global budgets. See **Totals calculation**.\n\n* * *\n\n#### 🏷️ **Discounts and surcharges** — `quote.discounts[]`, `quote.surcharges[]`\n\nBoth arrays share the same shape.\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier. |\n| `name` | `string` | Name shown to the customer. |\n| `description` | \\`string | null\\` |\n| `type` | `string` | How the amount is expressed. One of: `\"percent\"`, `\"global\"` (fixed amount). |\n| `entityApplicated` | `string` | What the adjustment applies to. One of: `\"item\"` (materials), `\"labor_force\"` (activities), `\"sub_total\"` (whole budget). |\n| `percent` | \\`number | null\\` |\n| `globalValue` | \\`number | null\\` |\n| `required` | \\`boolean | null\\` |\n\n* * *\n\n#### 📎 **Attachments** — `quote.attachments[]`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier. |\n| `name` | \\`string | null\\` |\n| `url` | `string` | Download URL. |\n\nOnly attachments explicitly marked to be shared with the customer are included. Internal attachments are never sent.\n\n* * *\n\n#### 💰 **Totals** — `quote.totals`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `subTotalQuote` | `number` | Sum of items and activities **before** any discount or surcharge. |\n| `baseItemsCost` | `number` | Items subtotal before adjustments. |\n| `baseActivitiesCost` | `number` | Activities subtotal before adjustments. |\n| `itemsCost` | `number` | Items subtotal **after** item-level discounts and surcharges. |\n| `activitiesCost` | `number` | Activities subtotal **after** labor-level discounts and surcharges. |\n| `totalItemDiscount` | `number` | Total discounted from items. |\n| `totalActivityDiscount` | `number` | Total discounted from activities. |\n| `totalSubTotalDiscount` | `number` | Total discounted from the subtotal. |\n| `totalDiscount` | `number` | Sum of all discounts. |\n| `totalSurcharge` | `number` | Sum of all surcharges. |\n| `totalQuote` | `number` | Final quoted amount, before commission. |\n| `totalPrice` | \\`number | null\\` |\n| `totalCost` | \\`number | null\\` |\n\n* * *\n\n#### 🧭 **Context**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `context.hasOriginBooking` | `boolean` | `true` when the budget originated from an existing booking. |\n| `context.originBookingId` | \\`number | null\\` |\n| `context.projectId` | \\`number | null\\` |\n| `context.customer` | \\`object | null\\` |\n| `context.provider` | \\`object | null\\` |\n| `context.address` | \\`object | null\\` |\n| `context.serviceVariantArea` | \\`object | null\\` |\n\n* * *\n\n#### 🧍 **Customer** — `context.customer`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack customer identifier. |\n| `name` | \\`string | null\\` |\n| `lastname` | \\`string | null\\` |\n| `email` | \\`string | null\\` |\n| `phone` | \\`string | null\\` |\n| `identification_number` | \\`string | null\\` |\n\n* * *\n\n#### 🛠️ **Provider** — `context.provider`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack provider identifier. |\n| `isCompany` | `boolean` | `true` when the provider is a company, `false` for an individual. |\n| `user.id` | `number` | Identifier of the provider's user account. |\n| `user.name` | \\`string | null\\` |\n| `user.lastname` | \\`string | null\\` |\n| `user.email` | \\`string | null\\` |\n| `user.phone` | \\`string | null\\` |\n| `user.identification_number` | \\`string | null\\` |\n\n* * *\n\n#### 🏠 **Address** — `context.address`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack address identifier. |\n| `address` | `string` | Address as entered. |\n| `formatted_address` | `string` | Normalized address. |\n| `coordinate` | \\`object | null\\` |\n| `coordinate.lng` | `number` | Longitude. |\n| `coordinate.lat` | `number` | Latitude. |\n\n* * *\n\n#### 🧩 **Service** — `context.serviceVariantArea`\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `id` | `number` | Unique Sodtrack identifier of the service variant area. |\n| `name` | \\`string | null\\` |\n| `description` | \\`string | null\\` |\n| `serviceVariant.id` | `number` | Service variant identifier. |\n| `serviceVariant.internal_name` | \\`string | null\\` |\n| `serviceVariant.skus` | `array` | SKUs associated with the variant, as `{ \"id\": number, \"sku\": string }`. Empty when none. |\n| `serviceVariant.service.id` | `number` | Service identifier. |\n| `serviceVariant.service.name` | \\`string | null\\` |\n| `serviceVariant.service.matchingType` | `object` | Provider matching strategy, as `{ \"id\": number, \"internalName\": string }`. |\n\n* * *\n\n### **Units of measure**\n\n`metric`, `productMetric` and related fields use one of the following values:\n\n`cm`, `mm`, `m`, `cm2`, `mm2`, `m2`, `cm3`, `mm3`, `m3`, `in`, `ft`, `yds`, `in2`, `ft2`, `yds2`, `in3`, `ft3`, `yds3`, `g`, `kg`, `t`, `oz`, `lbs`, `mlts`, `lts`, `gal`, `min`, `hrs`, `day`, `month`, `u`, `box`\n\n* * *\n\n### **Payload Example**\n\n```json\n{\n  \"quote\": {\n    \"type\": \"itemized\",\n    \"description\": \"Replacement of the damaged section of the potable water main, floors 3 to 5.\",\n    \"items\": [\n      {\n        \"id\": 366,\n        \"name\": \"Sealing kit\",\n        \"description\": \"Includes clamps, seals and structural adhesive\",\n        \"sku\": null,\n        \"type\": \"material\",\n        \"costType\": \"total\",\n        \"quantity\": null,\n        \"metric\": null,\n        \"metricCost\": null,\n        \"totalCost\": 100,\n        \"lineTotal\": 100,\n        \"required\": false\n      },\n      {\n        \"id\": 367,\n        \"name\": \"PVC pipe 50mm\",\n        \"description\": \"Sanitary PVC pipe, class 10\",\n        \"sku\": \"PVC-50-C10\",\n        \"type\": \"material\",\n        \"costType\": \"metric\",\n        \"quantity\": 200,\n        \"metric\": \"cm2\",\n        \"metricCost\": 1,\n        \"totalCost\": null,\n        \"lineTotal\": 200,\n        \"required\": false\n      }\n    ],\n    \"activities\": [\n      {\n        \"id\": 818,\n        \"name\": \"Debris removal\",\n        \"description\": \"Removal and final disposal of demolished material\",\n        \"order\": null,\n        \"quantity\": null,\n        \"metric\": null,\n        \"costPerMetric\": null,\n        \"typeCost\": \"global\",\n        \"globalCost\": 100,\n        \"lineTotal\": 100,\n        \"required\": null,\n        \"products\": []\n      },\n      {\n        \"id\": 819,\n        \"name\": \"Water network installation\",\n        \"description\": \"Cut, replacement and pressure test of the affected section\",\n        \"order\": null,\n        \"quantity\": 100,\n        \"metric\": \"m\",\n        \"costPerMetric\": 1,\n        \"typeCost\": \"metric\",\n        \"globalCost\": null,\n        \"lineTotal\": 100,\n        \"required\": null,\n        \"products\": []\n      }\n    ],\n    \"discounts\": [\n      {\n        \"id\": 176,\n        \"name\": \"Fixed discount\",\n        \"description\": \"Agreed with the account executive\",\n        \"type\": \"global\",\n        \"entityApplicated\": \"labor_force\",\n        \"percent\": null,\n        \"globalValue\": 100,\n        \"required\": null\n      },\n      {\n        \"id\": 177,\n        \"name\": \"Percentage discount\",\n        \"description\": \"Frequent customer\",\n        \"type\": \"percent\",\n        \"entityApplicated\": \"labor_force\",\n        \"percent\": 10,\n        \"globalValue\": null,\n        \"required\": null\n      }\n    ],\n    \"surcharges\": [\n      {\n        \"id\": 120,\n        \"name\": \"Fixed surcharge\",\n        \"description\": \"Crew transfer outside the urban radius\",\n        \"type\": \"global\",\n        \"entityApplicated\": \"labor_force\",\n        \"percent\": null,\n        \"globalValue\": 100,\n        \"required\": null\n      },\n      {\n        \"id\": 121,\n        \"name\": \"Percentage surcharge\",\n        \"description\": \"Work at height\",\n        \"type\": \"percent\",\n        \"entityApplicated\": \"labor_force\",\n        \"percent\": 10,\n        \"globalValue\": null,\n        \"required\": null\n      }\n    ],\n    \"attachments\": [],\n    \"totals\": {\n      \"subTotalQuote\": 500,\n      \"baseItemsCost\": 300,\n      \"baseActivitiesCost\": 200,\n      \"itemsCost\": 300,\n      \"activitiesCost\": 200,\n      \"totalItemDiscount\": 0,\n      \"totalActivityDiscount\": 120,\n      \"totalSubTotalDiscount\": 0,\n      \"totalDiscount\": 120,\n      \"totalSurcharge\": 120,\n      \"totalQuote\": 500,\n      \"totalPrice\": 500,\n      \"totalCost\": 400\n    }\n  },\n  \"context\": {\n    \"hasOriginBooking\": true,\n    \"originBookingId\": 2686,\n    \"projectId\": null,\n    \"customer\": {\n      \"id\": 7178,\n      \"name\": \"Alex\",\n      \"lastname\": null,\n      \"email\": \"alex.customer@example.com\",\n      \"phone\": \"3107406842\",\n      \"identification_number\": \"3107406842\"\n    },\n    \"provider\": {\n      \"id\": 11,\n      \"isCompany\": false,\n      \"user\": {\n        \"id\": 137,\n        \"name\": \"Sam\",\n        \"lastname\": \"Rivera\",\n        \"email\": \"sam.provider@example.com\",\n        \"phone\": \"+573107406842\",\n        \"identification_number\": \"1233696062\"\n      }\n    },\n    \"address\": {\n      \"id\": 6472,\n      \"address\": \"Comandante Chacón 5650, 8500048 Quinta Normal, Región Metropolitana, Chile\",\n      \"formatted_address\": \"Comandante Chacón 5650, 8500048 Quinta Normal, Región Metropolitana, Chile\",\n      \"coordinate\": {\n        \"lng\": -70.7134606,\n        \"lat\": -33.4286826\n      }\n    },\n    \"serviceVariantArea\": {\n      \"id\": 4790,\n      \"name\": \"\",\n      \"description\": null,\n      \"serviceVariant\": {\n        \"id\": 1764,\n        \"internal_name\": \"Door budget\",\n        \"service\": {\n          \"id\": 999,\n          \"name\": \"Door budgets\",\n          \"matchingType\": {\n            \"id\": 2,\n            \"internalName\": \"all_eligible_at_once\"\n          }\n        },\n        \"skus\": []\n      }\n    }\n  }\n}\n\n```\n\n* * *\n\n# Business Rules & Constraints\n\n## When the webhook is sent\n\nThe payload is delivered once, at the moment the budget is submitted to the customer for review. It is not resent when the customer approves or rejects the budget, and it is not resent if the budget is edited after submission.\n\nIf a budget is sent to the customer more than once, a new payload is delivered on each submission, reflecting the budget as it stands at that time.\n\n## Booking-backed and standalone budgets\n\n| Scenario | Behavior |\n| --- | --- |\n| `hasOriginBooking` is `true` | The budget was created from an existing booking. `originBookingId` identifies it, and `projectId` is populated when the booking belongs to a project. |\n| `hasOriginBooking` is `false` | The budget was created on its own. `originBookingId` and `projectId` are `null`. |\n\n`quote` is identical in both scenarios: the priced content of a budget does not depend on how the budget was created. `context.customer`, `context.provider`, `context.address` and `context.serviceVariantArea` are always resolved and populated regardless of the scenario.\n\n## Totals calculation\n\nAmounts are resolved in this order:\n\n1.  Items and activities are added up separately, producing `baseItemsCost` and `baseActivitiesCost`.\n    \n2.  Discounts and surcharges targeting `\"item\"` are applied to the items subtotal, and those targeting `\"labor_force\"` to the activities subtotal, producing `itemsCost` and `activitiesCost`.\n    \n3.  The two adjusted subtotals are added together.\n    \n4.  Discounts and surcharges targeting `\"sub_total\"` are applied to that result, producing `totalQuote`.\n    \n5.  The configured commission is applied to `totalQuote`, producing `totalPrice` and `totalCost`.\n    \n\nBecause subtotal-level adjustments are applied **after** item and labor adjustments, a percentage discount on `\"sub_total\"` is calculated over the already-adjusted amount, not over `subTotalQuote`.\n\nActivity products are **not** included in this calculation for budgets where `quote.type` is `\"itemized\"` or `\"global\"`. They are delivered as a detail of the work, not as a priced line. Summing `products[].lineTotal` and adding it to the totals will not match `totalQuote`.\n\n## Pricing models\n\n| `quote.type` | Behavior |\n| --- | --- |\n| `\"itemized\"` | `items` and `activities` carry the priced content. `totalQuote` is derived from them. |\n| `\"global\"` | The budget is quoted as a single amount. `items` and `activities` may be empty and the amount is carried in `subTotalQuote`. |\n| `null` | Legacy budget. `totals` is still complete, but discounts and surcharges are reported as `0`. |\n\n## Commission and provider amount\n\n`totalPrice` is what the customer pays and `totalCost` is what the provider receives. Depending on the commission configured for the service, the commission may be charged to the customer (`totalPrice` is higher than `totalQuote`), deducted from the provider (`totalCost` is lower than `totalQuote`), or both amounts may equal `totalQuote` when no commission applies to that side.\n\nWhen a fixed provider commission is configured with a value greater than the quoted amount, `totalCost` can be **negative**. Treat this as a configuration issue on the budget rather than a valid payable amount.\n\nBoth fields are `null` when the budget has no commission configured.\n\n## Amount format\n\nAll amounts are numeric values in the currency of the budget's operation. The payload does not carry a currency code; agree on the expected currency with Sodtrack during integration setup.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "quote": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "items": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "sku": {
                              "type": "null"
                            },
                            "type": {
                              "type": "string"
                            },
                            "costType": {
                              "type": "string"
                            },
                            "quantity": {
                              "type": "null"
                            },
                            "metric": {
                              "type": "null"
                            },
                            "metricCost": {
                              "type": "null"
                            },
                            "totalCost": {
                              "type": "integer"
                            },
                            "lineTotal": {
                              "type": "integer"
                            },
                            "required": {
                              "type": "boolean"
                            }
                          }
                        }
                      },
                      "activities": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "order": {
                              "type": "null"
                            },
                            "quantity": {
                              "type": "null"
                            },
                            "metric": {
                              "type": "null"
                            },
                            "costPerMetric": {
                              "type": "null"
                            },
                            "typeCost": {
                              "type": "string"
                            },
                            "globalCost": {
                              "type": "integer"
                            },
                            "lineTotal": {
                              "type": "integer"
                            },
                            "required": {
                              "type": "null"
                            },
                            "products": {
                              "type": "array",
                              "items": {}
                            }
                          }
                        }
                      },
                      "discounts": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "type": {
                              "type": "string"
                            },
                            "entityApplicated": {
                              "type": "string"
                            },
                            "percent": {
                              "type": "null"
                            },
                            "globalValue": {
                              "type": "integer"
                            },
                            "required": {
                              "type": "null"
                            }
                          }
                        }
                      },
                      "surcharges": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "integer"
                            },
                            "name": {
                              "type": "string"
                            },
                            "description": {
                              "type": "string"
                            },
                            "type": {
                              "type": "string"
                            },
                            "entityApplicated": {
                              "type": "string"
                            },
                            "percent": {
                              "type": "null"
                            },
                            "globalValue": {
                              "type": "integer"
                            },
                            "required": {
                              "type": "null"
                            }
                          }
                        }
                      },
                      "attachments": {
                        "type": "array",
                        "items": {}
                      },
                      "totals": {
                        "type": "object",
                        "properties": {
                          "subTotalQuote": {
                            "type": "integer"
                          },
                          "baseItemsCost": {
                            "type": "integer"
                          },
                          "baseActivitiesCost": {
                            "type": "integer"
                          },
                          "itemsCost": {
                            "type": "integer"
                          },
                          "activitiesCost": {
                            "type": "integer"
                          },
                          "totalItemDiscount": {
                            "type": "integer"
                          },
                          "totalActivityDiscount": {
                            "type": "integer"
                          },
                          "totalSubTotalDiscount": {
                            "type": "integer"
                          },
                          "totalDiscount": {
                            "type": "integer"
                          },
                          "totalSurcharge": {
                            "type": "integer"
                          },
                          "totalQuote": {
                            "type": "integer"
                          },
                          "totalPrice": {
                            "type": "integer"
                          },
                          "totalCost": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  },
                  "context": {
                    "type": "object",
                    "properties": {
                      "hasOriginBooking": {
                        "type": "boolean"
                      },
                      "originBookingId": {
                        "type": "integer"
                      },
                      "projectId": {
                        "type": "null"
                      },
                      "customer": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "lastname": {
                            "type": "null"
                          },
                          "email": {
                            "type": "string"
                          },
                          "phone": {
                            "type": "string"
                          },
                          "identification_number": {
                            "type": "string"
                          }
                        }
                      },
                      "provider": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "isCompany": {
                            "type": "boolean"
                          },
                          "user": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "lastname": {
                                "type": "string"
                              },
                              "email": {
                                "type": "string"
                              },
                              "phone": {
                                "type": "string"
                              },
                              "identification_number": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      },
                      "address": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "address": {
                            "type": "string"
                          },
                          "formatted_address": {
                            "type": "string"
                          },
                          "coordinate": {
                            "type": "object",
                            "properties": {
                              "lng": {
                                "type": "number"
                              },
                              "lat": {
                                "type": "number"
                              }
                            }
                          }
                        }
                      },
                      "serviceVariantArea": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "null"
                          },
                          "serviceVariant": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "internal_name": {
                                "type": "string"
                              },
                              "service": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "matchingType": {
                                    "type": "object",
                                    "properties": {
                                      "id": {
                                        "type": "integer"
                                      },
                                      "internalName": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "skus": {
                                "type": "array",
                                "items": {}
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "quote": {
                  "type": "itemized",
                  "description": "Excepteur aute elit consectetur sit veniam enim amet excepteur eu. Aute cillum reprehenderit cillum aliqua incididunt duis ex aute aliquip commodo aliquip pariatur quis amet excepteur. Adipisicing sunt magna est anim est amet aliquip Lorem officia dolore non qui exercitation cillum dolor. Lorem do non labore tempor. Veniam nostrud adipisicing est mollit.",
                  "items": [
                    {
                      "id": 366,
                      "name": "Material costo total",
                      "description": "test",
                      "sku": null,
                      "type": "material",
                      "costType": "total",
                      "quantity": null,
                      "metric": null,
                      "metricCost": null,
                      "totalCost": 100,
                      "lineTotal": 100,
                      "required": false
                    },
                    {
                      "id": 364,
                      "name": "Componente 1",
                      "description": "Esta es la descripción",
                      "sku": "1",
                      "type": "component",
                      "costType": "metric",
                      "quantity": 1,
                      "metric": "u",
                      "metricCost": 0,
                      "totalCost": null,
                      "lineTotal": 0,
                      "required": false
                    },
                    {
                      "id": 367,
                      "name": "Material costo por métrica",
                      "description": "Test",
                      "sku": null,
                      "type": "material",
                      "costType": "metric",
                      "quantity": 200,
                      "metric": "cm2",
                      "metricCost": 1,
                      "totalCost": null,
                      "lineTotal": 200,
                      "required": false
                    },
                    {
                      "id": 365,
                      "name": "Producto 6",
                      "description": null,
                      "sku": "6",
                      "type": "product",
                      "costType": "metric",
                      "quantity": 1,
                      "metric": "u",
                      "metricCost": 0,
                      "totalCost": null,
                      "lineTotal": 0,
                      "required": false
                    }
                  ],
                  "activities": [
                    {
                      "id": 818,
                      "name": "Actividad con costo total",
                      "description": "Test",
                      "order": null,
                      "quantity": null,
                      "metric": null,
                      "costPerMetric": null,
                      "typeCost": "global",
                      "globalCost": 100,
                      "lineTotal": 100,
                      "required": null,
                      "products": []
                    },
                    {
                      "id": 819,
                      "name": "Actrivida con costo por métrica",
                      "description": "Test",
                      "order": null,
                      "quantity": 100,
                      "metric": "m",
                      "costPerMetric": 1,
                      "typeCost": "metric",
                      "globalCost": null,
                      "lineTotal": 100,
                      "required": null,
                      "products": []
                    }
                  ],
                  "discounts": [
                    {
                      "id": 176,
                      "name": "Descuento fijo",
                      "description": "test",
                      "type": "global",
                      "entityApplicated": "labor_force",
                      "percent": null,
                      "globalValue": 100,
                      "required": null
                    },
                    {
                      "id": 177,
                      "name": "Descuento procentual",
                      "description": "Test",
                      "type": "percent",
                      "entityApplicated": "labor_force",
                      "percent": 10,
                      "globalValue": null,
                      "required": null
                    }
                  ],
                  "surcharges": [
                    {
                      "id": 120,
                      "name": "Recargo fijo",
                      "description": "Test",
                      "type": "global",
                      "entityApplicated": "labor_force",
                      "percent": null,
                      "globalValue": 100,
                      "required": null
                    },
                    {
                      "id": 121,
                      "name": "Recargo procentual",
                      "description": "Test",
                      "type": "percent",
                      "entityApplicated": "labor_force",
                      "percent": 10,
                      "globalValue": null,
                      "required": null
                    }
                  ],
                  "attachments": [],
                  "totals": {
                    "subTotalQuote": 500,
                    "baseItemsCost": 300,
                    "baseActivitiesCost": 200,
                    "itemsCost": 300,
                    "activitiesCost": 200,
                    "totalItemDiscount": 0,
                    "totalActivityDiscount": 120,
                    "totalSubTotalDiscount": 0,
                    "totalDiscount": 120,
                    "totalSurcharge": 120,
                    "totalQuote": 500,
                    "totalPrice": 500,
                    "totalCost": -500
                  }
                },
                "context": {
                  "hasOriginBooking": true,
                  "originBookingId": 2686,
                  "projectId": null,
                  "customer": {
                    "id": 7178,
                    "name": "Stiven",
                    "lastname": null,
                    "email": "stiven.jimenez+cliente@sodtrack.com",
                    "phone": "3107406842",
                    "identification_number": "3107406842"
                  },
                  "provider": {
                    "id": 11,
                    "isCompany": false,
                    "user": {
                      "id": 137,
                      "name": "Stiven's",
                      "lastname": "Jimenez",
                      "email": "stiven.jimenez+proveedor@sodtrack.com",
                      "phone": "+573107406842",
                      "identification_number": "1233696062"
                    }
                  },
                  "address": {
                    "id": 6472,
                    "address": "Comandante Chacón 5650, 8500048 Quinta Normal, Región Metropolitana, Chile",
                    "formatted_address": "Comandante Chacón 5650, 8500048 Quinta Normal, Región Metropolitana, Chile",
                    "coordinate": {
                      "lng": -70.7134606,
                      "lat": -33.4286826
                    }
                  },
                  "serviceVariantArea": {
                    "id": 4790,
                    "name": "",
                    "description": null,
                    "serviceVariant": {
                      "id": 1764,
                      "internal_name": "Presupuesto puerta",
                      "service": {
                        "id": 999,
                        "name": "Presupuestos puertas",
                        "matchingType": {
                          "id": 2,
                          "internalName": "all_eligible_at_once"
                        }
                      },
                      "skus": []
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    },
    "TransactionCreatedEvent": {
      "post": {
        "operationId": "webhookTransactioncreatedevent",
        "summary": "TransactionCreatedEvent",
        "description": "## **Purpose**\n\nThe **ExternalTransactionCreatedEvent** webhook notifies subscribers when a financial transaction has been successfully created and recorded within the **Sodtrack** platform.\n\nThe transaction is recorded with all associated booking and addon movements, enabling **comprehensive financial tracking**.\n\nIntegrating this webhook allows client systems to automatically:\n\n-   Synchronize payment records,\n    \n-   Trigger financial workflows (e.g., accounting updates, invoice generation, revenue recognition, reconciliation), and\n    \n-   Maintain **real-time financial consistency** with Sodtrack.\n    \n\n* * *\n\n### **Trigger Condition**\n\nThis webhook is triggered when:\n\n1.  A **financial transaction** (payment or refund) is successfully **created and validated** in the Sodtrack system, and\n    \n2.  The transaction is **associated with a shopping cart** and includes all related **booking and addon movements**.\n    \n\n* * *\n\n## **Example Use Cases**\n\n-   Automatically synchronize payment and refund records in external accounting systems, ERPs, or financial platforms.\n    \n-   Trigger post-transaction workflows such as invoice generation, receipt delivery, or revenue recognition.\n    \n-   Maintain synchronized financial records between Sodtrack and third-party systems.\n    \n-   Track payment status and reconcile transactions across multiple sources.\n    \n-   Generate financial reports and analytics based on transaction patterns.\n    \n\n* * *\n\n## Body\n\n| Field | Type | Description | Always |\n| --- | --- | --- | --- |\n| createdDate | Date | Date/time when the external transaction was created. | ✅ |\n| id | number | Unique transaction identifier. | ✅ |\n| reference | string | Transaction external reference. | ❌ |\n| extraInfo | string | Additional information or context provided by external system. | ❌ |\n| amount | number | Transaction amount in the selected currency. | ✅ |\n| status | string | Current transaction status. | ❌ |\n| type | string | Transaction type (`payment` | `refund`). |\n| currency.id | number | Currency identifier. | ✅ |\n| currency.name | string | Currency name. | ✅ |\n| shoppingCartId | number | Identifier linking the transaction to a shopping cart/stage. | ❌ |\n\n* * *\n\n### 💸 **externalTransaction.bookingTransactionMovements\\[\\]**\n\n|  | Type | Description | Always |\n| --- | --- | --- | --- |\n| bookingId | number | Affected booking identifier. | ✅ |\n| bookingReference | string | Booking external reference. | ❌ |\n| currency.id | number | Currency identifier for this movement. | ❌ |\n| currency.name | string | Currency name for this movement. | ❌ |\n\n* * *\n\n### 🔹 bookingTransactionMovements\\[\\].addonMovement\\[\\] (optional array)\n\n| Field | Type | Description | Always |\n| --- | --- | --- | --- |\n| addonId | number | Identifier of the add-on affected. | ❌ |\n| reference | string | Add-on external reference. | ❌ |\n| amount | number | Monetary adjustment affecting this add-on. | ❌ |\n| quantityAdjustment | number | Added/removed add-on units. | ❌ |\n\n* * *\n\n### 🔹 bookingTransactionMovements\\[\\].serviceMovement (optional)\n\n|  | Type | Description | Always |\n| --- | --- | --- | --- |\n| addonId | number | Identifier of the service variant addon (if applicable). | ❌ |\n| sku | string\\[\\] | SKUs associated with the service movement. | ❌ |\n| amount | number | Monetary adjustment affecting the service. | ❌ |\n| quantityAdjustment | number | Added/removed service quantity. | ❌ |\n\n* * *\n\n### 📝 **externalTransaction.dynamicFormSnapshotFields\\[\\]**\n\n| Field | Type | Description | Always |\n| --- | --- | --- | --- |\n| reference | string | Dynamic field external reference. | ❌ |\n| value | string | Captured value at the moment of the transaction. | ❌ |",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "timestamp": {
                    "type": "string"
                  },
                  "userTriggererEmail": {
                    "type": "string"
                  },
                  "externalTransaction": {
                    "type": "object",
                    "properties": {
                      "createdDate": {
                        "type": "string"
                      },
                      "id": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "extraInfo": {
                        "type": "string"
                      },
                      "amount": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "currency": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "shoppingCartId": {
                        "type": "string"
                      },
                      "bookingTransactionMovements": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "bookingId": {
                              "type": "string"
                            },
                            "bookingReference": {
                              "type": "string"
                            },
                            "currency": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "name": {
                                  "type": "string"
                                }
                              }
                            },
                            "addonMovement": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "addonId": {
                                    "type": "string"
                                  },
                                  "reference": {
                                    "type": "string"
                                  },
                                  "amount": {
                                    "type": "string"
                                  },
                                  "quantityAdjustment": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "serviceMovement": {
                              "type": "object",
                              "properties": {
                                "addonId": {
                                  "type": "string"
                                },
                                "sku": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "amount": {
                                  "type": "string"
                                },
                                "quantityAdjustment": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      },
                      "dynamicFormSnapshotFields": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reference": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "timestamp": "string",
                "userTriggererEmail": "string",
                "externalTransaction": {
                  "createdDate": "Date",
                  "id": "number",
                  "reference": "string",
                  "extraInfo": "string",
                  "amount": "number",
                  "status": "string",
                  "type": "string",
                  "currency": {
                    "id": "number",
                    "name": "string"
                  },
                  "shoppingCartId": "number",
                  "bookingTransactionMovements": [
                    {
                      "bookingId": "number",
                      "bookingReference": "string",
                      "currency": {
                        "id": "number",
                        "name": "string"
                      },
                      "addonMovement": [
                        {
                          "addonId": "number",
                          "reference": "string",
                          "amount": "number",
                          "quantityAdjustment": "number"
                        }
                      ],
                      "serviceMovement": {
                        "addonId": "number",
                        "sku": [
                          "string"
                        ],
                        "amount": "number",
                        "quantityAdjustment": "number"
                      }
                    }
                  ],
                  "dynamicFormSnapshotFields": [
                    {
                      "reference": "string",
                      "value": "string"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your endpoint's response to the event."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Obtain a token from `POST /api/authentication/generateJWT`."
      }
    }
  }
}