{
  "openapi": "3.0.0",
  "info": {
    "title": "Platomico API",
    "description": "The HTTP API behind Platomico. Authenticate with `Authorization: API <key>`.",
    "version": "2026-09-22"
  },
  "servers": [
    {
      "url": "https://api.platomico.com"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/authentication/session": {
      "get": {
        "operationId": "AuthController_getCurrentSession",
        "summary": "Get current user session",
        "description": "Returns the session attached to the Bearer token for a human user.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Current user session details"
          },
          "401": {
            "description": "Missing or invalid token"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/device/session": {
      "get": {
        "operationId": "AuthController_getDeviceSession",
        "summary": "Get current device session",
        "description": "Returns the session attached to the Bearer token for a paired device (POS, kiosk, etc.).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Current device session details"
          },
          "401": {
            "description": "Missing or invalid token"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/device/session/ephimeral": {
      "post": {
        "operationId": "AuthController_exchangeEphimeralSession",
        "summary": "Exchange an ephemeral code for a short-lived session",
        "description": "Used during device sign-up: the client trades the one-time code received via email/SMS for an ephemeral session that can complete device registration.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.Code"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Short-lived ephemeral session token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-up/device": {
      "post": {
        "operationId": "AuthController_signUpFromDevice",
        "summary": "Complete device sign-up",
        "description": "Creates the company, primary location, and device records using an ephemeral session obtained from /device/session/ephimeral.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.SignUpFromDevice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device session after successful sign-up"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-up/web": {
      "post": {
        "operationId": "AuthController_signUpFromWeb",
        "summary": "Sign up from the web",
        "description": "Creates a new user account. Requires a verification token from /sign-up/web/verify-code.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.SignUpFromWeb"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created user session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-up/web/request-code": {
      "post": {
        "operationId": "AuthController_requestSignUpFromWebCode",
        "summary": "Request a sign-up verification code",
        "description": "Sends a one-time code to the email to prove ownership before allowing sign-up.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Email to verify, plus optional preferred locale for the message",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "example": "user@platomico.com"
                  },
                  "locale": {
                    "type": "string",
                    "example": "es",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Code dispatched"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-up/web/verify-code": {
      "post": {
        "operationId": "AuthController_verifySignUpFromWebCode",
        "summary": "Verify a sign-up code",
        "description": "Validates the code emailed in the previous step and returns a verificationToken to use in /sign-up/web.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "code"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "example": "user@platomico.com"
                  },
                  "code": {
                    "type": "string",
                    "example": "482913"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification token to attach to /sign-up/web",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "verificationToken": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/member/session": {
      "get": {
        "operationId": "AuthController_getMemberSession",
        "summary": "Get current member session",
        "description": "Returns the session for a signed-in member (staff user of a company).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Current member session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/customer/session": {
      "get": {
        "operationId": "AuthController_getCustomerSession",
        "summary": "Get current customer session",
        "description": "Returns the session for a signed-in end customer.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Current customer session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/endpoint/session": {
      "get": {
        "operationId": "AuthController_getEndpointSession",
        "summary": "Get the endpoint session for a domain",
        "description": "Looks up the endpoint session bound to a (domain, scope) pair. Used by embedded frontends (ordering, QR) to bootstrap a session tied to their host.",
        "parameters": [
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "description": "Domain requesting the endpoint session",
            "example": "order.platomico.com",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "scope",
            "required": false,
            "in": "query",
            "description": "Optional scope for the endpoint session",
            "example": "order",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint session for the given domain/scope"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/session/exchange": {
      "post": {
        "operationId": "AuthController_exchangeSession",
        "summary": "Switch the active company on the user session",
        "description": "Exchanges the current user session for one scoped to another company the user belongs to.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "companyId"
                ],
                "properties": {
                  "companyId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New session with the target company active"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/session/agent-token": {
      "post": {
        "operationId": "AuthController_mintAgentSession",
        "summary": "Mint a company-restricted token for an AI agent",
        "description": "Issues a token for an agent or other machine client, restricted to one company the user belongs to. Unlike /session/exchange the result carries only that company, cannot be exchanged for another, and expires on its own schedule.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "companyId"
                ],
                "properties": {
                  "companyId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A token restricted to the target company"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/customer/session/exchange": {
      "post": {
        "operationId": "AuthController_exchangeCustomerSession",
        "summary": "Exchange a customer session",
        "description": "Upgrades or re-scopes a customer session (e.g. attaching a real name and target company after an anonymous start).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.ExchangeCustomerSession"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Exchanged customer session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-member-code": {
      "post": {
        "operationId": "AuthController_signInWithMemberCode",
        "summary": "Sign a member in from a device using a member code",
        "description": "Allows a member to start a session on a paired device by typing their numeric member code.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.MemberCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-member-code/endpoint": {
      "post": {
        "operationId": "AuthController_signInWithMemberCodeFromEndpoint",
        "summary": "Sign a member in from an endpoint using a member code",
        "description": "Same as /sign-in/with-member-code but scoped to an endpoint (embedded web) session instead of a device session.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.MemberCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/remote/access-code": {
      "post": {
        "operationId": "AuthController_createRemoteAccessCode",
        "summary": "Create a remote access code",
        "description": "A member issues a short-lived remote access code that another device can redeem to perform a specific action (e.g. unlock a cash register).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.CreateRemoteAccessCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated access code",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "code": "a1b2c3d4"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/check/access-code": {
      "post": {
        "operationId": "AuthController_checkRemoteAccessCode",
        "summary": "Check a remote access code",
        "description": "Verifies that a given remote access code is valid for the calling member without consuming it.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.AccessCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Whether the code is valid and its associated payload"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-customer-credentials": {
      "post": {
        "operationId": "AuthController_signInWithCustomer",
        "summary": "Sign a customer in from an endpoint",
        "description": "Creates or reuses a customer record and returns a customer session for an endpoint (e.g. ordering site).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.CustomerLoginPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/token": {
      "get": {
        "operationId": "AuthController_getToken",
        "summary": "Fetch a token by lookup key",
        "description": "Retrieves a previously stored token for the given lookup key and user type. Used in flows that need to resume a handoff by reference.",
        "parameters": [
          {
            "name": "key",
            "required": true,
            "in": "query",
            "description": "Lookup key for the stored token",
            "example": "sess_01H7A3B8K2MN5PQZX9YFVT",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userType",
            "required": true,
            "in": "query",
            "description": "Type of user the token belongs to",
            "example": "USER",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stored token payload"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-access-code": {
      "post": {
        "operationId": "AuthController_signInWithAccessCode",
        "summary": "Sign in with a remote access code",
        "description": "Redeems a remote access code issued by a member to authorize a one-off action.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.AccessCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session or action payload associated with the code"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-credentials": {
      "post": {
        "operationId": "AuthController_signInWithEmailAndPassword",
        "summary": "Sign in with email + password",
        "description": "Standard user sign-in. Returns a user session on success.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.Credentials"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User session"
          },
          "401": {
            "description": "Invalid credentials"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-email/device": {
      "post": {
        "operationId": "AuthController_signInWithEmailFromDevice",
        "summary": "Request a device sign-in email",
        "description": "Sends a one-time magic link or code to the user so they can sign in on a device.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.Email"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email dispatched"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-member-credentials": {
      "post": {
        "operationId": "AuthController_signInWithMemberCredentials",
        "summary": "Sign a member in with email + code",
        "description": "Verifies the numeric code previously emailed/sent to the member and returns a member session.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.MemberSignIn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member session"
          },
          "401": {
            "description": "Invalid or expired code"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/forgot-password": {
      "post": {
        "operationId": "AuthController_forgotUserPassword",
        "summary": "Send a password recovery email",
        "description": "Sends the user a link/code they can use to reset their password.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Email to recover, plus optional preferred locale",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "example": "user@platomico.com"
                  },
                  "locale": {
                    "type": "string",
                    "example": "es",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recovery email dispatched"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/check-user": {
      "post": {
        "operationId": "AuthController_checkExistingUser",
        "summary": "Check whether a user exists and is valid",
        "description": "Given a user id, returns whether the user exists and is in a valid state. Used by downstream services during account reconciliation.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existence/validity report"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/sign-in/with-device-code": {
      "post": {
        "operationId": "AuthController_signInWithDeviceCode",
        "summary": "Sign in with a device pairing code",
        "description": "Completes device pairing by redeeming the short code shown on the device.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.DeviceCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device session"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/send-code": {
      "post": {
        "operationId": "AuthController_sendMessageCode",
        "summary": "Send an SMS verification code",
        "description": "Sends a code to the customer's phone using the selected SMS provider.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.SmsPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS dispatched"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/verify-code": {
      "post": {
        "operationId": "AuthController_verifyMessageCode",
        "summary": "Verify an SMS code",
        "description": "Validates a code previously sent via /send-code and attaches the phone to the customer's session.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/authentication.SmsPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification result"
          }
        },
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/authentication/health": {
      "get": {
        "operationId": "HealthController_check",
        "summary": "Service health check",
        "description": "Returns the health status of the authentication service and its dependencies. Used by load balancers and uptime monitors.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Health details per subsystem",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "mongodb": {
                      "status": "up"
                    },
                    "redis": {
                      "status": "up"
                    },
                    "authentication-service": {
                      "status": "up"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Health"
        ]
      }
    },
    "/operations/companies/settings": {
      "get": {
        "operationId": "CompaniesController_fetchSettings",
        "summary": "Fetch company settings",
        "description": "Returns the active company profile and settings for the signed-in user (branding, billing, socials, legal, feature flags).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Company profile and settings",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "name": "Tacos Platomico",
                    "country": "ES",
                    "active": true,
                    "visible": true,
                    "billing": {
                      "taxId": "B12345678",
                      "businessName": "Tacos Platomico SL"
                    },
                    "settings": {
                      "links": {
                        "emitInvoiceURL": "https://platomico.com/invoices/emit"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Companies"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "CompaniesController_updateSettings",
        "summary": "Update company settings",
        "description": "Updates branding, billing, name/type or logo on the active company. Requires admin-level roles.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateSettings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated company settings"
          }
        },
        "tags": [
          "Companies"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/companies/status/device": {
      "get": {
        "operationId": "CompaniesController_fetchStatusFromDevice",
        "summary": "Fetch company status from a device",
        "description": "Used by paired devices to read the company onboarding/operational status without pulling the full settings payload.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Company operational status",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "COMPLETED",
                    "active": true,
                    "visible": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Companies"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/roles": {
      "get": {
        "operationId": "RolesController_fetch",
        "summary": "List roles",
        "description": "Returns roles belonging to the caller company, optionally filtered by location ids.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Roles visible to the caller",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "69ca70599588542b854b5503",
                      "name": "Rider",
                      "type": "user:courier",
                      "permissions": [
                        "read:users",
                        "accept:offers"
                      ],
                      "active": true,
                      "visible": true,
                      "isSystem": true
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "RolesController_create",
        "summary": "Create a role",
        "description": "Creates a new role for the active company and locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.Role"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created role"
          }
        },
        "tags": [
          "Roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "RolesController_update",
        "summary": "Update a role",
        "description": "Partial update of a role record.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateRole"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated role"
          }
        },
        "tags": [
          "Roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "RolesController_remove",
        "summary": "Delete a role",
        "description": "Deactivates a role. Fails when members are still assigned to it.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "69ca70599588542b854b5503",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/roles/one": {
      "get": {
        "operationId": "RolesController_fetchById",
        "summary": "Fetch a role by id",
        "description": "Returns the full role document for the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "69ca70599588542b854b5503",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Role details"
          }
        },
        "tags": [
          "Roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users": {
      "get": {
        "operationId": "UsersController_fetchUsers",
        "summary": "List users for the active company",
        "description": "Returns every user that belongs to the caller active company (and its sub-companies where applicable).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Users in the active company",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9e5",
                      "name": "Maria Gomez",
                      "email": "maria@tacosplatomico.com",
                      "role": "Admin",
                      "active": true
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "UsersController_updateUser",
        "summary": "Update a user",
        "description": "Partial update of a user record (name, email, role). Requires the target userId in the body. The caller may only update a user ranked strictly below them, and may only assign a role strictly below their own.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "UpdateUser payload with explicit userId",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId",
                  "locale"
                ],
                "properties": {
                  "userId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e5"
                  },
                  "name": {
                    "type": "string",
                    "example": "Maria Gomez"
                  },
                  "email": {
                    "type": "string",
                    "example": "maria@tacosplatomico.com"
                  },
                  "role": {
                    "type": "string",
                    "example": "Admin"
                  },
                  "locale": {
                    "type": "string",
                    "example": "es"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated user"
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "UsersController_deleteUser",
        "summary": "Delete a user",
        "description": "Disables a user (soft delete: active and visible are cleared). The caller may only delete a user ranked strictly below them.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId"
                ],
                "properties": {
                  "userId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/me": {
      "patch": {
        "operationId": "UsersController_updateOwnProfile",
        "summary": "Update the signed-in user own profile",
        "description": "Self-service partial update of the caller own name, phone and avatar. The target is always the session user; it never accepts a userId.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOwnUser"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile updated",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/me/password": {
      "post": {
        "operationId": "UsersController_changeOwnPassword",
        "summary": "Change the signed-in user own password",
        "description": "Requires the current password. Returns reason currentPasswordInvalid (401) or weakPassword (400) on failure.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ChangeOwnPassword"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password changed",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "passwordUpdatedAt": "2026-08-03T10:00:00.000Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/me/notifications": {
      "get": {
        "operationId": "UsersController_fetchOwnNotifications",
        "summary": "Read the signed-in user email notification preferences",
        "description": "Missing preferences resolve to enabled, so a user who never touched them gets both switches on.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Notification preferences",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "closingSummary": {
                      "enabled": true
                    },
                    "lowStock": {
                      "enabled": true
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "UsersController_updateOwnNotifications",
        "summary": "Update the signed-in user email notification preferences",
        "description": "Accepts a partial payload; omitted channels keep their value.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOwnNotifications"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preferences updated",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/invite": {
      "post": {
        "operationId": "UsersController_invite",
        "summary": "Invite a user",
        "description": "Sends an invitation email to the given address. The user can then set a password and access the active company. The caller may only invite a role strictly below their own (OWNER > ADMIN > MANAGER > STAFF > VIEWER).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.InviteUser"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invitation dispatched",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "inviteId": "invite_abc123",
                    "email": "maria@tacosplatomico.com",
                    "status": "SENT"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/resend-invite": {
      "post": {
        "operationId": "UsersController_resendInvite",
        "summary": "Resend a user invitation",
        "description": "Resends the invitation email for an existing (not yet activated) user. Useful when the original email expired.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId",
                  "locale"
                ],
                "properties": {
                  "userId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e5"
                  },
                  "locale": {
                    "type": "string",
                    "example": "es"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invitation dispatched"
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/activate": {
      "patch": {
        "operationId": "UsersController_activateUser",
        "summary": "Activate a user",
        "description": "Marks a user as active so they can sign in to the dashboard. The caller may only activate a user ranked strictly below them.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userId"
                ],
                "properties": {
                  "userId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Activation result"
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/validate-invite": {
      "post": {
        "operationId": "UsersController_validateInvite",
        "summary": "Validate an invite key",
        "description": "Public endpoint that checks whether an invitation key (from an invitation email) is still valid and returns its payload.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invite validation result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "valid": true,
                    "email": "maria@tacosplatomico.com",
                    "companyId": "64f1b8a2c3d4e5f6a7b8c9c0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/complete-invite": {
      "post": {
        "operationId": "UsersController_completeInvite",
        "summary": "Complete an invite",
        "description": "Public endpoint that finalizes an invitation: sets the password for the invited user and activates their account.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key",
                  "password"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "password": {
                    "type": "string",
                    "example": "correcthorsebatterystaple"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Activated user session"
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/update-password": {
      "post": {
        "operationId": "UsersController_updatePassword",
        "summary": "Update a user password",
        "description": "Public endpoint that finalizes a password recovery flow: validates the temp id and sets the new password.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Password update payload",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tempId",
                  "userId",
                  "companyId",
                  "password"
                ],
                "properties": {
                  "tempId": {
                    "type": "string",
                    "example": "tmp_abc123"
                  },
                  "userId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e5"
                  },
                  "companyId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9c0"
                  },
                  "password": {
                    "type": "string",
                    "example": "correcthorsebatterystaple"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password updated"
          }
        },
        "tags": [
          "Users"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/health": {
      "get": {
        "operationId": "HealthController_check",
        "summary": "Check operations service health",
        "description": "Public liveness probe that reports the health status of the operations service and its critical dependencies.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Health details for each critical dependency",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "mongodb": {
                      "status": "up"
                    },
                    "redis": {
                      "status": "up"
                    },
                    "operations-service": {
                      "status": "up"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Health"
        ]
      }
    },
    "/operations/payments/by-hour": {
      "get": {
        "operationId": "PaymentsController_fetchCashByHour",
        "summary": "Fetch cash payments by hour",
        "description": "Aggregates cash payment totals per hour of day within the window, for the requested locations. Used for cash-handling reports.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cash payment totals per hour",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "currency": "EUR",
                    "hours": [
                      {
                        "hour": 12,
                        "total": 15000
                      },
                      {
                        "hour": 13,
                        "total": 22000
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/payments": {
      "get": {
        "operationId": "PaymentsController_fetchTotalByLocations",
        "summary": "Fetch total payments by location",
        "description": "Returns payment totals grouped by location for the given time window. Covers every tender type (cash, card, online).",
        "parameters": [
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End of the window (ISO 8601)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start of the window (ISO 8601)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Totals grouped by location",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "currency": "EUR",
                    "byLocation": {
                      "64f1b8a2c3d4e5f6a7b8c9d0": 850000,
                      "64f1b8a2c3d4e5f6a7b8c9d1": 400000
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/roles": {
      "get": {
        "operationId": "UserRolesController_fetch",
        "summary": "List dashboard user roles",
        "description": "Named page-access profiles for the caller company. A role lists the route paths its holders may open — anything absent is hidden from the sidebar and blocked on navigation — and optionally the location ids its holders may see; an empty `locationIds` means every location.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Roles in the company",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "69ca70599588542b854b5503",
                      "name": "Finance",
                      "permissions": [
                        "/analytics/sales",
                        "/analytics/finance"
                      ],
                      "locationIds": [],
                      "active": true,
                      "visible": true,
                      "isSystem": false
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "User roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "UserRolesController_create",
        "summary": "Create a dashboard user role",
        "description": "Route paths are stored as given; unknown paths are harmless (they simply match no page) but a renamed route silently stops being granted.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UserRole"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created role",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "69ca70599588542b854b5503",
                    "name": "Finance",
                    "permissions": [
                      "/analytics/sales",
                      "/analytics/finance"
                    ],
                    "locationIds": [],
                    "active": true,
                    "visible": true,
                    "isSystem": false
                  }
                }
              }
            }
          }
        },
        "tags": [
          "User roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "UserRolesController_update",
        "summary": "Update a dashboard user role",
        "description": "Partial update. `permissions` and `locationIds` each replace their whole list — send the full set, not a delta.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateUserRole"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated role",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "69ca70599588542b854b5503",
                    "name": "Finance",
                    "permissions": [
                      "/analytics/sales",
                      "/analytics/finance"
                    ],
                    "locationIds": [],
                    "active": true,
                    "visible": true,
                    "isSystem": false
                  }
                }
              }
            }
          }
        },
        "tags": [
          "User roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "UserRolesController_remove",
        "summary": "Delete a dashboard user role",
        "description": "Soft delete. Refused with 400 while any user still holds the role, because detaching it would silently widen their access to everything.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "deleted": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "User roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/users/roles/one": {
      "get": {
        "operationId": "UserRolesController_fetchById",
        "summary": "Read one dashboard user role",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The role",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "69ca70599588542b854b5503",
                    "name": "Finance",
                    "permissions": [
                      "/analytics/sales",
                      "/analytics/finance"
                    ],
                    "locationIds": [],
                    "active": true,
                    "visible": true,
                    "isSystem": false
                  }
                }
              }
            }
          }
        },
        "tags": [
          "User roles"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations": {
      "post": {
        "operationId": "LocationsController_create",
        "summary": "Create a location (deprecated)",
        "description": "Legacy location creation endpoint. New integrations should use POST /locations/v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateLocation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created location"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "LocationsController_fetch",
        "summary": "List locations",
        "description": "Returns every location accessible to the signed-in user. Optional locationsIds filter returns only matching ids.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Locations accessible to the caller",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Tacos Platomico - Sol",
                      "status": "OPERATIONAL",
                      "settings": {
                        "currency": "EUR",
                        "timezone": "Europe/Madrid"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/v2": {
      "post": {
        "operationId": "LocationsController_createV2",
        "summary": "Create a location (v2)",
        "description": "Creates a physical location for the active company with currency, timezone, branding, workdays and ticket settings.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateLocationV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created location"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/device": {
      "get": {
        "operationId": "LocationsController_fetchFromDevice",
        "summary": "Fetch the location attached to a device",
        "description": "Returns the location bound to the calling device session. Used at device boot to load currency/timezone/printers.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Location attached to the device session"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/fetch-by-companies": {
      "get": {
        "operationId": "LocationsController_fetchByCompanies",
        "summary": "List locations across all reachable companies",
        "description": "Returns locations for every company the user belongs to. Useful for multi-brand dashboards.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Locations grouped by company"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/workdays": {
      "patch": {
        "operationId": "LocationsController_updateWorkdays",
        "summary": "Update workdays for one or more locations",
        "description": "Replaces the weekly workdays schedule (opening hours) for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateWorkdaysDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update result"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/delivery-live-timers": {
      "get": {
        "operationId": "LocationsController_fetchDeliveryLiveTimers",
        "summary": "Fetch per-location timer settings for the live kanban",
        "description": "Returns the deliveryLiveTimers block for each requested location, with defaults filled in when not yet configured.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to fetch timer settings for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-location timer settings",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "timers": {
                        "enabled": true,
                        "columns": {
                          "enPreparacion": {
                            "soonMinutes": 5,
                            "lateMinutes": 10
                          },
                          "esperandoRecogida": {
                            "soonMinutes": 5,
                            "lateMinutes": 10
                          },
                          "enReparto": {
                            "soonMinutes": 10,
                            "lateMinutes": 20
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "put": {
        "operationId": "LocationsController_updateDeliveryLiveTimers",
        "summary": "Update timer settings for a single location",
        "description": "Upserts the deliveryLiveTimers block on settings. Validates that values come from the allowed minutes set and that \"late\" >= \"soon\".",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateDeliveryLiveTimersDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated timer settings"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/tickets": {
      "patch": {
        "operationId": "LocationsController_updateTickets",
        "summary": "Update ticket printing flags",
        "description": "Replaces the ticket printing configuration (receipt, kitchenReceipt) for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateTicketsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update result"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/auto-print": {
      "patch": {
        "operationId": "LocationsController_updateAutoPrint",
        "summary": "Update automatic printing exclusions",
        "description": "Replaces the per-source and per-device auto-print deny lists for the given locations. An order whose source or originating device is listed is still rendered and stored, but never printed automatically — an operator can reprint it from the POS or the KDS. Absent or empty lists mean every order auto-prints.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateAutoPrintDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update result"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/pos": {
      "patch": {
        "operationId": "LocationsController_updatePos",
        "summary": "Update POS behaviour flags",
        "description": "Replaces the POS behaviour configuration (e.g. autoComplete on \"Done\") for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdatePosDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update result"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/locations/endpoint": {
      "get": {
        "operationId": "LocationsController_fetchFromEndpoint",
        "summary": "Fetch locations for an endpoint session",
        "description": "Returns the locations available to the calling endpoint session (embedded ordering/QR frontends), optionally filtered by ids.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Locations for the endpoint"
          }
        },
        "tags": [
          "Locations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/gross/sales": {
      "get": {
        "operationId": "AnalyticsController_fetchGrossSales",
        "summary": "Fetch gross sales totals",
        "description": "Returns the gross sales (before discounts and refunds) for the given locations within the time window. Used by dashboards to present top-line revenue.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Gross sales totals keyed by location",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "total": 1250000,
                    "currency": "EUR",
                    "byLocation": {
                      "64f1b8a2c3d4e5f6a7b8c9d0": 850000,
                      "64f1b8a2c3d4e5f6a7b8c9d1": 400000
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/net/sales": {
      "get": {
        "operationId": "AnalyticsController_fetchNetSales",
        "summary": "Fetch net sales totals",
        "description": "Returns net sales (gross minus discounts, refunds and taxes) for the given locations within the time window.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Net sales totals keyed by location",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "total": 1100000,
                    "currency": "EUR",
                    "byLocation": {
                      "64f1b8a2c3d4e5f6a7b8c9d0": 720000,
                      "64f1b8a2c3d4e5f6a7b8c9d1": 380000
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/sales-by-hour": {
      "get": {
        "operationId": "AnalyticsController_fetchSalesByHour",
        "summary": "Fetch sales aggregated by hour of day",
        "description": "Returns sales totals bucketed by hour of day (0-23). Used to render hourly distribution charts and staffing insights.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Narrow to one service type. DINE_IN, TAKE_AWAY or DELIVERY; ALL or absent leaves every order in.",
            "example": "DELIVERY",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Narrow to one origin, matched exactly against the order's stored source. Marketplace orders carry the provider's own name, so 'Glovo' selects that marketplace alone. ALL or absent leaves every origin in.",
            "example": "Glovo",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sales totals per hour of the day (0-23)",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "currency": "EUR",
                    "hours": [
                      {
                        "hour": 12,
                        "total": 45000
                      },
                      {
                        "hour": 13,
                        "total": 62000
                      },
                      {
                        "hour": 14,
                        "total": 58000
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/times/by-location": {
      "get": {
        "operationId": "AnalyticsController_fetchTimesByLocation",
        "summary": "Fetch operational times grouped by location and day",
        "description": "Returns per-location, per-day sums and counts (for weighted averages) of preparation time (stored prepTime), waiting-pickup time (order doneAt → linked delivery pickedUpAt) and delivery time (pickedUpAt → deliveredAt), all in milliseconds. Metrics without valid samples return zero counts so clients can hide them.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results by calendar day",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Time sums/counts per location per day",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "date": "2026-07-13",
                      "prepTimeTotal": 5400000,
                      "prepTimeCount": 9,
                      "waitingPickupTotal": 1200000,
                      "waitingPickupCount": 4,
                      "deliveryTimeTotal": 4800000,
                      "deliveryTimeCount": 4
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/items/sales-amount": {
      "get": {
        "operationId": "AnalyticsController_fetchItemsSalesAmount",
        "summary": "Fetch per-item sales amounts",
        "description": "Returns total sold amount per menu item across the given locations and time window. Used for top-sellers reports.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate item sales for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-item sales amounts",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "itemId": "64f1b8a2c3d4e5f6a7b8c9e0",
                      "name": "Cheeseburger",
                      "totalAmount": 45000,
                      "totalItems": 120,
                      "currency": "EUR"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/delivery/metrics": {
      "get": {
        "operationId": "AnalyticsController_fetchDeliveryMetrics",
        "summary": "Fetch delivery KPI metrics for a date range",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/delivery/metrics/by-location": {
      "get": {
        "operationId": "AnalyticsController_fetchDeliveryMetricsByLocation",
        "summary": "Fetch delivery KPI metrics grouped by location",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/delivery/orders/by-location": {
      "get": {
        "operationId": "AnalyticsController_fetchDeliveryOrdersByLocation",
        "summary": "Fetch individual delivery orders for a location and date range",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/delivery/stacks/{stackIdentifier}": {
      "get": {
        "operationId": "AnalyticsController_fetchDeliveryStackDetail",
        "summary": "Fetch delivery stack detail scoped to the current company",
        "parameters": [
          {
            "name": "stackIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/delivery/fleets": {
      "get": {
        "operationId": "AnalyticsController_fetchClientFleets",
        "summary": "Fetch delivery fleets serving the current company",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/delivery/offers/summary": {
      "get": {
        "operationId": "AnalyticsController_fetchDeliveryOffersSummary",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/v2/delivery/metrics": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_fetchDeliveryMetrics",
        "summary": "Fetch delivery metrics (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel (prep-time stats)",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type (prep-time stats)",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/v2/delivery/metrics/by-location": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_fetchDeliveryMetricsByLocation",
        "summary": "Fetch delivery metrics by location (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel (prep-time stats)",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type (prep-time stats)",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/v2/times/by-location": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_fetchTimesByLocation",
        "summary": "Fetch operational times by location and day (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel (prep-time stats)",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type (prep-time stats)",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/analytics/v2/orders/prep-time-stats": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_fetchPrepTimeStats",
        "summary": "Fetch prep-time statistics (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate analytics for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel (prep-time stats)",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type (prep-time stats)",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device": {
      "get": {
        "operationId": "OrdersController_fetchOrdersFromDevice",
        "summary": "List orders from a device",
        "description": "Returns orders visible to the calling device, filtered by state and station. Used by kitchen/kds devices to render their queue. When the company has settings.kds.readinessScope = STATION, item ready flags are projected from the calling device station overlay (cross-outs are per-station) and the stationReadiness container is stripped. When settings.kds.expeditionHoldUntilPrepared is true, EXPEDITION devices only receive open tickets once preparation finished every visible line (cancellations always pass; SEQUENTIAL-flow tickets are exempt). When settings.kds.hideFromPreparationOncePrepared is true, the mirror applies: PREPARATION devices stop receiving an open ticket once every visible line is prepared, so it only remains visible on EXPEDITION.",
        "parameters": [
          {
            "name": "state",
            "required": false,
            "in": "query",
            "description": "Lifecycle states to include",
            "example": [
              "PENDING",
              "IN_PROCESS"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "stationId",
            "required": false,
            "in": "query",
            "description": "Station identifier to restrict results to",
            "example": "STATION_KITCHEN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Orders visible to the device",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9f2",
                      "state": "IN_PROCESS",
                      "priority": 10,
                      "items": [
                        {
                          "name": "Cheeseburger",
                          "quantity": 2
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "OrdersController_updateOrderState",
        "summary": "Update order state from a device",
        "description": "Moves the order to a new state (PENDING, IN_PROCESS, COMPLETED, CANCELLED) from a device (KDS or POS).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrderState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated order"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/by-id": {
      "get": {
        "operationId": "OrdersController_fetchOrderByIdFromDevice",
        "summary": "Fetch an order by id from a device",
        "description": "Returns the full order document for a single id, scoped to the calling device. When the company has settings.kds.readinessScope = STATION, item ready flags are projected from the calling device station overlay (cross-outs are per-station) and the stationReadiness container is stripped. When settings.kds.expeditionHoldUntilPrepared is true, a ticket still held from EXPEDITION returns null, exactly like a not-found id. When settings.kds.hideFromPreparationOncePrepared is true, a ticket that finished preparation returns null to PREPARATION devices the same way.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Order identifier to fetch",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order details"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/item-sales": {
      "get": {
        "operationId": "OrdersController_fetchOrdersWithSpecificItems",
        "summary": "Get aggregated specific item sales (range/month best year)",
        "description": "Gets aggregated item sales from Transactions:V2 for items whose name matches the provided `itemName` (case-insensitive substring).\n\n- With both `from` and `to` dates (YYYY-MM-DD): returns sales for the date range (createdAt, totalSales, totalItems, bestYear).\n- Without `from` and `to`: compares the current month across all years and returns the best year for that month.\n\nRequires authentication: use API key with \"API \" prefix, e.g. API Pk-XXXxxxxxxXXXXXXX-xxXX-xXXXXX",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location identifier to scope the item sales.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "itemName",
            "required": true,
            "in": "query",
            "description": "Substring to match in `order.items.name` (case-insensitive). Example: \"combo\", \"burger\", etc.",
            "example": "burger",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start date (YYYY-MM-DD). Required if `to` is provided.",
            "example": "2026-01-01",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End date (YYYY-MM-DD). Required if `from` is provided.",
            "example": "2026-04-30",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated specific item sales for the best performing year/day: { createdAt, totalSales, totalItems, bestYear }",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "createdAt": "2024-12-17T10:59:42.923Z",
                    "totalSales": 2190,
                    "totalItems": 2,
                    "bestYear": 2024
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "statusCode": 403,
                    "message": "Forbidden resource",
                    "error": "Forbidden"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          },
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/orders/prep-time-stats": {
      "get": {
        "operationId": "OrdersController_fetchPrepTimeStats",
        "summary": "Fetch prep-time statistics",
        "description": "Returns average / p50 / p95 order preparation times for the given locations and time window. Used by operations dashboards.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to aggregate prep-time stats for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start of the analysis window (ISO 8601)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End of the analysis window (ISO 8601)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Prep-time statistics",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "avgSeconds": 480,
                    "p50Seconds": 420,
                    "p95Seconds": 900,
                    "sampleSize": 1250
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/ernesto": {
      "get": {
        "operationId": "OrdersController_fetchOrdersWithSpecificItemsErnesto",
        "summary": "Ernesto: specific item sales for a date range",
        "description": "Bespoke analytics endpoint for the Ernesto dashboard. Returns per-item sales aggregated across the range for items whose names contain the substring.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "itemName",
            "required": true,
            "in": "query",
            "example": "burger",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-01-01",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-04-30",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-item sales aggregate"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/ernesto/record": {
      "get": {
        "operationId": "OrdersController_fetchOrdersWithSpecificItemsRecord",
        "summary": "Ernesto: best-day record for item names",
        "description": "Bespoke analytics endpoint for the Ernesto dashboard. Returns the single day with the highest daily item sales inside the range for any of the comma-separated item names.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "itemNames",
            "required": true,
            "in": "query",
            "example": "burger,combo",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-01-01",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-04-30",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Best day record",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "date": "2026-04-18",
                    "totalSales": 12500,
                    "totalItems": 42
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/kanban": {
      "get": {
        "operationId": "OrdersController_fetchKanbanWindow",
        "summary": "Real-time kanban window of recent orders",
        "description": "Returns Transactions:Orders updated in the last 2 hours for the given locations (DRAFT and CANCELLED excluded), plus the matching Delivery:Orders documents (joined via trace.deliveryId). The frontend derives column placement (En preparación / Esperando recogida / En reparto / Entregados). When both `from` and `to` are supplied the endpoint instead returns orders created within that historical window (including cancelled orders, still excluding drafts), for the review table.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to include in the kanban view",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Optional start of a historical window (ISO 8601). Requires `to`.",
            "example": "2026-07-03T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "Optional end of a historical window (ISO 8601). Requires `from`.",
            "example": "2026-07-03T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kanban window payload",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "orders": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9f2",
                        "reference": "A-0042",
                        "state": "IN_PROCESS",
                        "fulfillmentType": "DELIVERY",
                        "deliveryId": "64f1b8a2c3d4e5f6a7b8c9f3",
                        "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "receivedAtIso": "2026-05-07T11:42:18.000Z",
                        "doneAtIso": null,
                        "deliveredAtIso": null,
                        "itemCounts": {
                          "topLevel": 3,
                          "expandMeals": 5
                        },
                        "total": {
                          "amount": 2450,
                          "currency": "EUR"
                        },
                        "customerName": "María L."
                      }
                    ],
                    "deliveries": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9f3",
                        "status": "ACCEPTED",
                        "courierUserIdentifier": "user-123",
                        "pickedUpAtIso": null,
                        "deliveredAtIso": null
                      }
                    ],
                    "generatedAtIso": "2026-05-07T11:48:00.000Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/kanban/stats": {
      "get": {
        "operationId": "OrdersController_fetchKanbanStats",
        "summary": "Aggregate stats for the kanban view",
        "description": "Returns averaged metrics for completed deliveries within the supplied window: prep time (Transactions:Orders), waiting time (kitchen done → courier pickup), delivery time (pickup → delivered), end-to-end (waiting + delivery), and orders per hour.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to scope the stats to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start of the analysis window (ISO 8601)",
            "example": "2026-05-06T15:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End of the analysis window (ISO 8601)",
            "example": "2026-05-07T15:00:00.000Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated kanban stats",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "prepTime": {
                      "averageMilliseconds": 540000,
                      "count": 14
                    },
                    "waitingTime": {
                      "averageMilliseconds": 180000,
                      "count": 12
                    },
                    "deliveryTime": {
                      "averageMilliseconds": 720000,
                      "count": 12
                    },
                    "endToEndTime": {
                      "averageMilliseconds": 900000
                    },
                    "ordersPerHour": {
                      "value": 0.5,
                      "ordersCount": 12,
                      "hours": 24
                    },
                    "windowFromIso": "2026-05-06T15:00:00.000Z",
                    "windowToIso": "2026-05-07T15:00:00.000Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/kanban/stats/timeseries": {
      "get": {
        "operationId": "OrdersController_fetchKanbanStatsTimeseries",
        "summary": "Per-day timeseries of the kanban stats",
        "description": "Returns one entry per day within the supplied window with averaged metrics: prep time (Transactions:Orders, bucketed by the day the kitchen finished), waiting time (kitchen done → courier pickup), delivery time (pickup → delivered) and end-to-end (prep + waiting + delivery). Days are bucketed in the first location timezone.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to scope the timeseries to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start of the analysis window (ISO 8601)",
            "example": "2026-05-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End of the analysis window (ISO 8601)",
            "example": "2026-05-31T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-day kanban stats",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "days": [
                      {
                        "dateIso": "2026-05-06",
                        "prepTime": {
                          "averageMilliseconds": 540000,
                          "count": 14
                        },
                        "waitingTime": {
                          "averageMilliseconds": 180000,
                          "count": 12
                        },
                        "deliveryTime": {
                          "averageMilliseconds": 720000,
                          "count": 12
                        },
                        "endToEndTime": {
                          "averageMilliseconds": 1440000
                        }
                      }
                    ],
                    "windowFromIso": "2026-05-01T00:00:00.000Z",
                    "windowToIso": "2026-05-31T23:59:59.999Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/live-operations": {
      "get": {
        "operationId": "OrdersController_fetchLiveOperations",
        "summary": "Per-location live operations rollup",
        "description": "Returns one row per location combining a compressed kanban flow (raw orders + stage entry timestamps) with KPI aggregates (orders, revenue, channel mix, prep/waiting/delivery averages, courier-at-door, cancellations) for the requested KPI window, plus quality metrics (transaction ratings + Google reviews) which always cover the whole day (location timezone) in live mode, or the explicit from/to range when supplied.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to include (one row per location is returned)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "kpiWindow",
            "required": false,
            "in": "query",
            "description": "KPI aggregation window. \"last60m\" (default) or \"today\" (start-of-day in each location timezone). Ignored when from/to are supplied.",
            "example": "last60m",
            "schema": {
              "enum": [
                "last60m",
                "today"
              ],
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Optional explicit window start (ISO 8601); with `to`, overrides kpiWindow.",
            "example": "2026-07-03T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "Optional explicit window end (ISO 8601). Requires `from`.",
            "example": "2026-07-03T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-location live operations payload"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/seen": {
      "patch": {
        "operationId": "OrdersController_markOrderSeen",
        "summary": "Stamp seenAt when a KDS device first renders an order",
        "description": "Sets seenAt on the order the first time any KDS device renders it. Idempotent: repeat calls (or races between devices) are a no-op and never overwrite the original stamp. Does not broadcast SSE.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.MarkOrderSeen"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stamp result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "updated": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/advance-station": {
      "patch": {
        "operationId": "OrdersController_advanceOrderStation",
        "summary": "Move a SEQUENTIAL-flow order to its next/previous station",
        "description": "Advances (or recalls with direction=BACK) an order along its stations-flow route, stamping the station visit history and broadcasting UPDATE_ORDER via SSE. Rejects orders without a SEQUENTIAL flow; 409 when already at the route boundary. EXPEDITION close still uses PATCH /device with state COMPLETED.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.AdvanceOrderStation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New route position and station pointers"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/item-ready": {
      "patch": {
        "operationId": "OrdersController_updateOrderItemReady",
        "summary": "Toggle the ready flag on an order item from a device",
        "description": "Sets the ready flag on an item, item modifier, meal step, or meal step modifier. Persisted on the order document and broadcast via SSE so other devices at the same location reconcile. When the company has settings.kds.readinessScope = STATION, the flag is stored in the calling station overlay (Order.stationReadiness) instead of items[*].ready, and the SSE event omits the change payload so each device refetches its own projection.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrderItemReady"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Item ready flag updated"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/items-ready": {
      "patch": {
        "operationId": "OrdersController_updateOrderItemsReady",
        "summary": "Toggle ready flags on multiple order slots from a device (atomic)",
        "description": "Applies a batch of ready-flag changes (items, item modifiers, meal steps, meal step modifiers) for a single order in one write, then broadcasts a single UPDATE_ORDER event via SSE. Use this instead of issuing many /device/item-ready calls. When the company has settings.kds.readinessScope = STATION, the batch is stored in the calling station overlay (Order.stationReadiness) instead of items[*].ready, and the SSE event omits the change payload so each device refetches its own projection.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrderItemsReady"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Item ready flags updated"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders": {
      "patch": {
        "operationId": "OrdersController_update",
        "summary": "Update an order",
        "description": "Updates an order (items, customer info, delivery info, state, priority). Called by the back-office or from the POS.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated order"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/v2": {
      "get": {
        "operationId": "OrdersDeviceV2Controller_fetchOrdersFromDevice",
        "summary": "List orders from a device (v2)",
        "description": "Returns every non-DRAFT order of the 24h window visible to the calling device, filtered by state and station. Unlike the legacy route, NEITHER settings.kds.expeditionHoldUntilPrepared NOR settings.kds.hideFromPreparationOncePrepared is applied: holding is a per-station release rule the screen evaluates from Order.stationCompletions, so a ticket leaves a screen only when a person says so. Item ready flags are ALWAYS projected from the calling device station overlay and the stationReadiness container is stripped, regardless of settings.kds.readinessScope: a cross-out is one station saying something about its own work, so a line crossed at PREPARATION does not appear crossed at EXPEDITION.",
        "parameters": [
          {
            "name": "state",
            "required": false,
            "in": "query",
            "description": "Lifecycle states to include",
            "example": [
              "PENDING",
              "IN_PROCESS"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "stationId",
            "required": false,
            "in": "query",
            "description": "Station identifier to restrict results to",
            "example": "STATION_KITCHEN",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Orders visible to the device",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9f2",
                      "state": "IN_PROCESS",
                      "priority": 10,
                      "items": [
                        {
                          "name": "Cheeseburger",
                          "quantity": 2
                        }
                      ],
                      "stationCompletions": {
                        "PREPARATION": {
                          "completedAt": "2026-08-12T19:12:04.512Z",
                          "deviceId": "64f1b8a2c3d4e5f6a7b8c9d1"
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Orders:Device:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "OrdersDeviceV2Controller_updateOrderState",
        "summary": "Update order state from a device (v2)",
        "description": "Same transition as the legacy route — timestamps, Sinqro/Square callbacks, billing usage events and the UPDATE_ORDER broadcast are identical — plus the calling station's own completion stamp: set on COMPLETED, cleared when the order is reopened. That is what puts a ticket back in expedition's open tab on undo instead of leaving it stuck in Completados by its own completion record. Other stations' stamps are never touched.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrderState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order state updated"
          }
        },
        "tags": [
          "Orders:Device:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/v2/by-id": {
      "get": {
        "operationId": "OrdersDeviceV2Controller_fetchOrderByIdFromDevice",
        "summary": "Fetch an order by id from a device (v2)",
        "description": "Returns the full order document for a single id, scoped to the calling device. Never withholds a ticket: NEW_ORDER is broadcast with no origin device, so every screen refetches by id at creation, and answering null would leave a held station without the document it needs to reveal the ticket once its release rule is satisfied. Projected through the calling station overlay, like the list.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Order identifier to fetch",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order details"
          }
        },
        "tags": [
          "Orders:Device:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/v2/items-ready": {
      "patch": {
        "operationId": "OrdersDeviceV2Controller_updateOrderItemsReady",
        "summary": "Toggle ready flags on multiple order slots from a device (v2)",
        "description": "Applies a batch of ready-flag changes (items, item modifiers, meal steps, meal step modifiers) for a single order in one write, then broadcasts one UPDATE_ORDER. Unlike the legacy route this ALWAYS stores them in the calling station's own overlay (Order.stationReadiness[stationId]) rather than the shared items[*].ready flags, and does not consult settings.kds.readinessScope: a tick means \"this station has done its part of this line\", so crossing a line at PREPARATION must not show it crossed at EXPEDITION. The broadcast names the writing station and omits the change list, so sibling screens of that station refetch their own projection and other stations ignore it.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrderItemsReady"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ready flags updated"
          }
        },
        "tags": [
          "Orders:Device:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/v2/item-ready": {
      "patch": {
        "operationId": "OrdersDeviceV2Controller_updateOrderItemReady",
        "summary": "Toggle the ready flag on one order slot from a device (v2)",
        "description": "One slot, same rule as the batch route: the flag lands in the calling station's overlay, never on the shared flags.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateOrderItemReady"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ready flag updated"
          }
        },
        "tags": [
          "Orders:Device:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/orders/device/v2/station-complete": {
      "patch": {
        "operationId": "OrdersDeviceV2Controller_setStationCompleted",
        "summary": "Record or clear one station completion of an order",
        "description": "Stamps Order.stationCompletions[stationId] with { completedAt, deviceId } (completed=false clears it), leaving the order's own state alone, and broadcasts UPDATE_ORDER carrying the updated map so every screen at the location can re-evaluate its release rule without refetching. This is the shared-completion replacement for the device-local hide a preparation station used to keep in its own storage; closing the whole order remains PATCH / with state COMPLETED. The station is taken from the body because a KDS can be re-pointed locally; unknown values fall back to the calling device's configured station.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.SetStationCompleted"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stamp result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "updated": true,
                    "stationId": "PREPARATION",
                    "completedAt": "2026-08-12T19:12:04.512Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders:Device:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/delivery": {
      "get": {
        "operationId": "DeliveryController_fetchOrders",
        "summary": "Fetch delivery orders for current company",
        "parameters": [
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "post": {
        "operationId": "DeliveryController_createOrder",
        "summary": "Create a delivery order for current company",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateDeliveryOrderDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/paged": {
      "get": {
        "operationId": "DeliveryController_fetchOrdersPage",
        "summary": "Fetch a page of delivery orders with the total matching the filter",
        "parameters": [
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/pickup-locations": {
      "get": {
        "operationId": "DeliveryController_fetchPickupLocations",
        "summary": "Fetch pickup locations authorized for current session",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/fleets": {
      "get": {
        "operationId": "DeliveryController_fetchFleets",
        "summary": "Fetch delivery fleets for current company",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/fleets/{fleetId}/locations": {
      "patch": {
        "operationId": "DeliveryController_updateFleetLocations",
        "summary": "Update locations covered by a fleet",
        "parameters": [
          {
            "name": "fleetId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/tracking": {
      "get": {
        "operationId": "DeliveryController_fetchActiveRiders",
        "summary": "Fetch active riders with their current location",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/tracking/order": {
      "get": {
        "operationId": "DeliveryController_fetchTrackingOrder",
        "summary": "Fetch delivery tracking details for a specific order and workday",
        "parameters": [
          {
            "name": "workdayId",
            "required": true,
            "in": "query",
            "schema": {}
          },
          {
            "name": "orderId",
            "required": true,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders": {
      "get": {
        "operationId": "DeliveryController_fetchRiders",
        "summary": "Fetch all riders (users with workdays) for current company",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders/{userIdentifier}/sessions/count": {
      "get": {
        "operationId": "DeliveryController_countRiderSessions",
        "summary": "Count workday sessions for a specific rider",
        "description": "Returns only the number of matching sessions. The list endpoint additionally resolves completed orders for every session; a caller paging the table needs the total, not that work.",
        "parameters": [
          {
            "name": "userIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders/{userIdentifier}/sessions": {
      "get": {
        "operationId": "DeliveryController_fetchRiderSessions",
        "summary": "Fetch workday sessions for a specific rider",
        "parameters": [
          {
            "name": "userIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders/{userIdentifier}/orders": {
      "get": {
        "operationId": "DeliveryController_fetchRiderActiveOrders",
        "summary": "Fetch active orders for a specific rider",
        "parameters": [
          {
            "name": "userIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders/{userIdentifier}/stats": {
      "get": {
        "operationId": "DeliveryController_fetchRiderStats",
        "summary": "Fetch hour stats for a specific rider",
        "parameters": [
          {
            "name": "userIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "month",
            "required": false,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/by-id": {
      "get": {
        "operationId": "DeliveryController_fetchOrderById",
        "summary": "Fetch a delivery order by ID",
        "parameters": [
          {
            "name": "orderId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/summary": {
      "get": {
        "operationId": "DeliveryController_fetchDeliverySummary",
        "summary": "Fetch delivery summary/KPIs for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/metrics": {
      "get": {
        "operationId": "DeliveryController_fetchDeliveryMetrics",
        "summary": "Fetch delivery operational KPIs for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders/metrics": {
      "get": {
        "operationId": "DeliveryController_fetchRiderMetrics",
        "summary": "Fetch per-rider performance metrics for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userIdentifier",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/riders/contract-summary": {
      "get": {
        "operationId": "DeliveryController_fetchRidersContractSummary",
        "summary": "Fetch per-rider assigned vs contracted hours for a date range",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fleetId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/fleets/metrics": {
      "get": {
        "operationId": "DeliveryController_fetchFleetMetrics",
        "summary": "Fetch per-fleet performance metrics for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fleetId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/reports/attendance": {
      "get": {
        "operationId": "DeliveryController_fetchAttendanceReport",
        "summary": "Fetch rider attendance report for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fleetId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/metrics/timeseries": {
      "get": {
        "operationId": "DeliveryController_fetchDeliveryTimeseries",
        "summary": "Fetch delivery time-series for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "hour",
                "day"
              ],
              "type": "string"
            }
          },
          {
            "name": "userIdentifier",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fleetId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/offers": {
      "get": {
        "operationId": "DeliveryController_fetchOffers",
        "summary": "Fetch delivery offers for current company",
        "parameters": [
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "userIdentifier",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/offers/by-id": {
      "get": {
        "operationId": "DeliveryController_fetchOfferById",
        "summary": "Fetch a delivery offer by ID",
        "parameters": [
          {
            "name": "offerId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/offers/by-order": {
      "get": {
        "operationId": "DeliveryController_fetchOffersByOrder",
        "summary": "Fetch offer book for a delivery order",
        "parameters": [
          {
            "name": "orderId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/offers/summary": {
      "get": {
        "operationId": "DeliveryController_fetchOfferSummary",
        "summary": "Fetch delivery offer summary/KPIs for current company",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/stacks/{stackIdentifier}": {
      "get": {
        "operationId": "DeliveryController_fetchStackDetail",
        "summary": "Fetch the composition of a delivery stack",
        "parameters": [
          {
            "name": "stackIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/support/requests/manage": {
      "get": {
        "operationId": "DeliveryController_fetchSupportRequests",
        "summary": "Fetch courier support requests for current company",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/support/requests/manage/paged": {
      "get": {
        "operationId": "DeliveryController_fetchSupportRequestsPage",
        "summary": "List a page of courier support requests with the matching total",
        "description": "Same filter as the list endpoint, narrowed to one page. Courier, fleet and resolver names are resolved only for the rows on the page.",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "example": "0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "example": "20",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Matches the request description, the courier name, and any issue or topic identifier listed in `labels`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "labels",
            "required": false,
            "in": "query",
            "description": "Issue or topic identifiers whose label matched the search term in the caller locale, resolved by the caller so the service stays locale-agnostic.",
            "schema": {
              "type": "array",
              "items": {}
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/support/requests/manage/count": {
      "get": {
        "operationId": "DeliveryController_countSupportRequests",
        "summary": "Count courier support requests for current company",
        "description": "Returns only the number of matching requests. The list endpoint additionally resolves courier, fleet and resolver names for every row; a caller rendering a badge needs none of that.",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/support/requests/{requestIdentifier}/status": {
      "patch": {
        "operationId": "DeliveryController_updateSupportRequestStatus",
        "summary": "Update the status of a courier support request",
        "parameters": [
          {
            "name": "requestIdentifier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateSupportRequestStatusDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/{orderId}/courier": {
      "patch": {
        "operationId": "DeliveryController_reassignCourier",
        "summary": "Reassign the courier for a delivery order",
        "parameters": [
          {
            "name": "orderId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ReassignCourierDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/{orderId}/cancel": {
      "patch": {
        "operationId": "DeliveryController_cancelOrder",
        "summary": "Cancel a delivery order",
        "parameters": [
          {
            "name": "orderId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CancelDeliveryOrderDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/couriers": {
      "post": {
        "operationId": "DeliveryController_inviteCourier",
        "summary": "Invite a new courier to a fleet",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.InviteCourier"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/couriers/{courierId}/locations": {
      "patch": {
        "operationId": "DeliveryController_updateCourierLocations",
        "summary": "Update locations covered by a courier",
        "parameters": [
          {
            "name": "courierId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateCourierLocationsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/couriers/{courierId}/configuration": {
      "patch": {
        "operationId": "DeliveryController_updateCourierConfiguration",
        "summary": "Update courier configuration (e.g. maximumActiveOrders)",
        "parameters": [
          {
            "name": "courierId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateCourierConfigurationDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "get": {
        "operationId": "DeliveryController_fetchCourierConfiguration",
        "summary": "Fetch courier configuration (e.g. maximumActiveOrders)",
        "parameters": [
          {
            "name": "courierId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/performance-thresholds": {
      "get": {
        "operationId": "DeliveryController_fetchPerformanceThresholds",
        "summary": "Fetch performance thresholds by scope (merchant:location)",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "patch": {
        "operationId": "DeliveryController_updatePerformanceThreshold",
        "summary": "Upsert the performance threshold for a scope (merchant:location)",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdatePerformanceThresholdDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/couriers/{courierId}": {
      "delete": {
        "operationId": "DeliveryController_deleteCourier",
        "summary": "Delete a courier",
        "parameters": [
          {
            "name": "courierId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/couriers/resend-invite": {
      "post": {
        "operationId": "DeliveryController_resendCourierInvite",
        "summary": "Resend courier invite email",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/delivery/couriers/password-reset/request": {
      "post": {
        "operationId": "DeliveryController_requestCourierPasswordReset",
        "summary": "Request a password reset email for a courier",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ]
      }
    },
    "/operations/delivery/couriers/password-reset/confirm": {
      "post": {
        "operationId": "DeliveryController_confirmCourierPasswordReset",
        "summary": "Confirm a courier password reset with token",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Delivery"
        ]
      }
    },
    "/operations/stations-flows": {
      "get": {
        "operationId": "StationsFlowsController_fetch",
        "summary": "Fetch the stations flows configured for the company",
        "description": "One flow per location. Locations without a flow simply have no document and behave as legacy (no routing).",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Optional location scope",
            "schema": {
              "type": "array",
              "items": {}
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Stations flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "put": {
        "operationId": "StationsFlowsController_upsert",
        "summary": "Create or replace the stations flow of a location",
        "description": "Validates that stations are unique, known, and end with EXPEDITION; then upserts the single flow document of the location and pushes a REFRESH_STATIONS_FLOW command to its devices. Route changes apply to NEW orders only.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location whose flow is being configured",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpsertStationsFlow"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Stations flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "StationsFlowsController_remove",
        "summary": "Delete the stations flow of a location",
        "description": "The location reverts to legacy behavior (no routing) for new orders; in-flight flow orders complete normally.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location whose flow is being removed",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Stations flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/stations-flows/device": {
      "get": {
        "operationId": "StationsFlowsController_fetchDeviceFlow",
        "summary": "Fetch the stations flow for the calling device location",
        "description": "Returns the flow document for the device session location, or null when the location has no flow configured.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Flow document or null"
          }
        },
        "tags": [
          "Stations flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/paginated": {
      "get": {
        "operationId": "InvoicesController_fetchPaginated",
        "summary": "List invoices (paginated)",
        "description": "Returns invoices belonging to the active company with optional text search and createdAt range, paginated with page/pageSize.",
        "parameters": [
          {
            "name": "page",
            "required": true,
            "in": "query",
            "example": "1",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSize",
            "required": true,
            "in": "query",
            "example": "25",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "example": "RCPT-2026",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAtFrom",
            "required": false,
            "in": "query",
            "example": "2026-01-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAtTo",
            "required": false,
            "in": "query",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated invoices",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "items": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9a3",
                        "receiptId": "RCPT-2026-0001",
                        "name": "Maria Gomez",
                        "total": 1250,
                        "currency": "EUR",
                        "date": "2026-04-23T12:00:00.000Z"
                      }
                    ],
                    "total": 42,
                    "page": 1,
                    "pageSize": 25
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/statistics": {
      "get": {
        "operationId": "InvoicesController_fetchStatistics",
        "summary": "Invoice totals for the active company",
        "description": "The figures behind the dashboard's invoice KPI strip: how many invoices were issued in the requested window and in the comparison window beside it, and what they add up to before and after tax. Honours the same `search` the paginated list takes, so the strip and the table it sits above always agree. The caller resolves both windows; this route only sums.",
        "parameters": [
          {
            "name": "createdAtFrom",
            "required": true,
            "in": "query",
            "example": "2026-09-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAtTo",
            "required": true,
            "in": "query",
            "example": "2026-09-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "previousCreatedAtFrom",
            "required": true,
            "in": "query",
            "example": "2026-08-02T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "previousCreatedAtTo",
            "required": true,
            "in": "query",
            "example": "2026-08-31T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "example": "FA0012",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice totals for the two windows, amounts in cents",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "period": {
                      "from": "2026-09-01T00:00:00.000Z",
                      "to": "2026-09-30T23:59:59.999Z",
                      "count": 248,
                      "total": 4812050,
                      "taxes": 834710,
                      "discount": 12500,
                      "currency": "EUR"
                    },
                    "previousPeriod": {
                      "from": "2026-08-02T00:00:00.000Z",
                      "to": "2026-08-31T23:59:59.999Z",
                      "count": 220,
                      "total": 4443120,
                      "taxes": 772180,
                      "discount": 9000,
                      "currency": "EUR"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices": {
      "get": {
        "operationId": "InvoicesController_fetchByCustomer",
        "summary": "Fetch invoices for a customer",
        "description": "Returns every invoice linked to the given customer id within the active company.",
        "parameters": [
          {
            "name": "customerId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoices linked to the customer",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9a3",
                      "receiptId": "RCPT-2026-0001",
                      "total": 1250,
                      "currency": "EUR"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "InvoicesController_create",
        "summary": "Create an invoice from a receipt",
        "description": "Generates an invoice number and persists the invoice for the given receipt. Legacy payload; prefer /endpoint or /dashboard.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateInvoice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created invoice"
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/transaction": {
      "get": {
        "operationId": "InvoicesController_fetchTransactionByReceiptId",
        "summary": "Fetch a transaction by receipt id + date",
        "description": "Looks up the transaction that generated the given receipt on the specified date. Used when the invoice flow starts from a printed ticket.",
        "parameters": [
          {
            "name": "receiptId",
            "required": true,
            "in": "query",
            "example": "RCPT-2026-0001",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date",
            "required": true,
            "in": "query",
            "example": "2026-04-23T12:00:00.000Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching transaction",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9a2",
                    "receiptId": "RCPT-2026-0001",
                    "total": 1250,
                    "currency": "EUR",
                    "items": [
                      {
                        "name": "Cheeseburger",
                        "quantity": 2,
                        "total": 900
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/{invoiceId}/pdf": {
      "get": {
        "operationId": "InvoicesController_downloadPdf",
        "summary": "Download invoice PDF",
        "description": "Streams the invoice PDF. Accepts an optional locale for the PDF copy (default: es). Sets content-disposition to attachment.",
        "parameters": [
          {
            "name": "invoiceId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9a3",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locale",
            "required": false,
            "in": "query",
            "example": "es",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF binary stream"
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/endpoint": {
      "post": {
        "operationId": "InvoicesController_createFromEndpoint",
        "summary": "Create an invoice from an endpoint",
        "description": "v2 invoice creation called from the embedded checkout (endpoint session). Requires the originating transactionId.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateInvoiceV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created invoice"
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/dashboard": {
      "post": {
        "operationId": "InvoicesController_createFromDashboard",
        "summary": "Create an invoice from the dashboard",
        "description": "v2 invoice creation called from the back-office dashboard. Internally maps the user session to an endpoint-like payload.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateInvoiceV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created invoice"
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/invoices/export-email": {
      "post": {
        "operationId": "InvoicesController_exportByEmail",
        "summary": "Export invoices by email",
        "description": "Enqueues an export job that sends a ZIP with the selected invoice PDFs to the target email address.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ExportInvoicesByEmail"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Export job queued",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "jobId": "job_abc123",
                    "queued": 42
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Invoices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/customers": {
      "get": {
        "operationId": "CustomerController_fetchAll",
        "summary": "List customers for the active company",
        "description": "Returns customers belonging to the caller company. Pagination kicks in when both page and pageSize are provided; otherwise the full list is returned. Supports optional text search and createdAt date range.",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "example": "1",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "example": "25",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "example": "maria",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAtFrom",
            "required": false,
            "in": "query",
            "example": "2026-01-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAtTo",
            "required": false,
            "in": "query",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customers matching the query",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "items": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "name": "Maria",
                        "lastname": "Gomez",
                        "email": "maria@example.com",
                        "phone": {
                          "prefix": "+34",
                          "number": "600123456"
                        }
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "pageSize": 25
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Customers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/customers/statistics": {
      "get": {
        "operationId": "CustomerController_fetchStatistics",
        "summary": "Customer-base statistics for the active company",
        "description": "Counts behind the dashboard's customer KPI strip: the whole base, how much of it carries an email and a phone, and — for the requested window and for the comparison window — how many customers arrived and how many already existed before it started. The caller resolves both windows; this route only counts.",
        "parameters": [
          {
            "name": "createdAtFrom",
            "required": true,
            "in": "query",
            "example": "2026-09-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAtTo",
            "required": true,
            "in": "query",
            "example": "2026-09-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "previousCreatedAtFrom",
            "required": true,
            "in": "query",
            "example": "2026-08-02T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "previousCreatedAtTo",
            "required": true,
            "in": "query",
            "example": "2026-08-31T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer-base counts for the two windows",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "total": 1204,
                    "withEmail": 940,
                    "withPhone": 812,
                    "period": {
                      "from": "2026-09-01T00:00:00.000Z",
                      "to": "2026-09-30T23:59:59.999Z",
                      "count": 87,
                      "baseBefore": 1117
                    },
                    "previousPeriod": {
                      "from": "2026-08-02T00:00:00.000Z",
                      "to": "2026-08-31T23:59:59.999Z",
                      "count": 64,
                      "baseBefore": 1053
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Customers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/reviews": {
      "get": {
        "operationId": "ReviewsController_fetch",
        "summary": "Fetch reviews",
        "description": "Returns every review (Google, in-house) received at the given locations during the time window.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to fetch reviews for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reviews for the locations",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9a6",
                      "author": "Maria G.",
                      "rating": 5,
                      "text": "Best tacos in Madrid!",
                      "source": "google",
                      "createdAt": "2026-04-20T12:00:00.000Z"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/reviews/dashboard": {
      "get": {
        "operationId": "ReviewsController_findDashboardReviews",
        "summary": "Fetch reviews for the dashboard",
        "description": "Returns the aggregated reviews view (totals, average rating, breakdown by rating) for the dashboard.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to fetch reviews for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated review metrics",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "total": 128,
                    "average": 4.6,
                    "byRating": {
                      "1": 2,
                      "2": 3,
                      "3": 8,
                      "4": 30,
                      "5": 85
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Reviews"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/reviews/v2": {
      "get": {
        "operationId": "ReviewsV2Controller_fetch",
        "summary": "Fetch reviews (v2)",
        "description": "v2 reviews endpoint which uses the new reviews collection (more sources, consolidated schema).",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to fetch reviews for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reviews for the locations",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9a6",
                      "author": "Maria G.",
                      "rating": 5,
                      "text": "Best tacos in Madrid!",
                      "source": "google",
                      "createdAt": "2026-04-20T12:00:00.000Z"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Reviews:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/reviews/v2/dashboard": {
      "get": {
        "operationId": "ReviewsV2Controller_findDashboardReviews",
        "summary": "Fetch reviews for the dashboard (v2)",
        "description": "v2 aggregated reviews view for dashboards (totals, averages, rating breakdown, source breakdown).",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to fetch reviews for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated review metrics",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "total": 128,
                    "average": 4.6,
                    "byRating": {
                      "1": 2,
                      "2": 3,
                      "3": 8,
                      "4": 30,
                      "5": 85
                    },
                    "bySource": {
                      "google": 95,
                      "inhouse": 33
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Reviews:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices": {
      "get": {
        "operationId": "DevicesController_fetchDevices",
        "summary": "List devices",
        "description": "Returns every device belonging to the active company, optionally filtered by location ids.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Devices matching the query",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9e0",
                      "type": "POS",
                      "name": "Front counter POS",
                      "status": "ACTIVE",
                      "trace": {
                        "locationId": "64f1b8a2c3d4e5f6a7b8c9d0"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "DevicesController_create",
        "summary": "Create a device",
        "description": "Registers a new device (POS, kiosk, printer, kitchen display) at a location.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateDevice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created device"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "DevicesController_updateDevice",
        "summary": "Update a device",
        "description": "Partially updates a device record (name, description, status, network, trace metadata).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateDevice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated device"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "DevicesController_deleteDevice",
        "summary": "Delete a device",
        "description": "Removes a device from the company. The device becomes unreachable and any remaining session is revoked.",
        "parameters": [
          {
            "name": "deviceId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/exec/action": {
      "post": {
        "operationId": "DevicesController_execAction",
        "summary": "Execute a remote action on devices",
        "description": "Broadcasts a command (LOGOUT, RELOAD) to the targeted device or all devices in the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ExecAction"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delivery result for the command",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "dispatched": 3
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/session": {
      "get": {
        "operationId": "DevicesController_fetchSession",
        "summary": "Fetch the current device session",
        "description": "Returns the device-scoped (or impersonating member) session for the Bearer token. Used by the device shell at boot.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Device or member session details",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "deviceId": "64f1b8a2c3d4e5f6a7b8c9e0",
                    "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "companyId": "64f1b8a2c3d4e5f6a7b8c9c0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/heartbeat": {
      "post": {
        "operationId": "DevicesController_postHeartbeat",
        "summary": "Post a device heartbeat",
        "description": "Called periodically by devices to report liveness, app/os version and platform. Updates the lastSeenAt field.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.PostHeartbeat"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Heartbeat acknowledged"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/peripheral-offline": {
      "post": {
        "operationId": "DevicesController_markPeripheralOffline",
        "summary": "Mark a USB peripheral as offline immediately",
        "description": "Called by a till the moment it observes a USB detach event. Pushes the matching peripheral record into the OFFLINE window so the admin UI reflects the disconnect without waiting on heartbeat ageing.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.PeripheralOffline"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Peripheral connectivity flipped to OFFLINE"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/preferences": {
      "get": {
        "operationId": "DevicesController_fetchDevicePreferences",
        "summary": "Fetch the calling device's own app preferences",
        "description": "Self-scoped: resolved from the session, never from a query. Pulled by the device after a REFRESH_SETTINGS command to re-apply its settings without restarting or rebuilding the whole session.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Stored preferences, sparse (absent key = client default)",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "preferences": {
                      "layoutId": "twoRail",
                      "textSize": "LARGE",
                      "items": {
                        "showMeals": false
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "DevicesController_updateDevicePreferences",
        "summary": "Update a device's app preferences",
        "description": "Partial patch, written key by key. Serves both directions: the dashboard names a deviceId, while a device calling it can only ever write its own (the body deviceId is ignored for device sessions). Dispatches a REFRESH_SETTINGS SSE command to the target unless the caller IS the target.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateDevicePreferences"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated device"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/linked": {
      "get": {
        "operationId": "DevicesController_fetchLinkedDevices",
        "summary": "List devices linked to the caller device",
        "description": "Returns every device that is paired with the caller device (e.g. printers or KDS attached to a POS).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Linked devices",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9f0",
                      "type": "PRINTER",
                      "name": "Kitchen printer"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/one": {
      "get": {
        "operationId": "DevicesController_getDeviceById",
        "summary": "Fetch a device by id",
        "description": "Returns the full device document for a single device id.",
        "parameters": [
          {
            "name": "deviceId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Device details"
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/code": {
      "get": {
        "operationId": "DevicesController_fetchDeviceCode",
        "summary": "Fetch a pairing code for a device",
        "description": "Generates (or returns a fresh) pairing code that can be entered on the physical device to complete pairing.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location the device belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deviceId",
            "required": true,
            "in": "query",
            "description": "Device to issue a pairing code for",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pairing code",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "code": "482913",
                    "expiresAt": "2026-04-23T12:10:00.000Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Devices"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/v2": {
      "post": {
        "operationId": "DevicesV2Controller_create",
        "summary": "Create a device (v2)",
        "description": "Registers a new device using the v2 creation pipeline which adds defaults and richer validation over the legacy endpoint.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateDevice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created device"
          }
        },
        "tags": [
          "Devices:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "DevicesV2Controller_updateDevice",
        "summary": "Update a device (v2)",
        "description": "Partially updates a device record using the v2 update pipeline. Should be preferred over the legacy PATCH endpoint.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateDevice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated device"
          }
        },
        "tags": [
          "Devices:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/settings/all": {
      "get": {
        "operationId": "SettingsController_fetchAll",
        "summary": "List every settings document for the company",
        "description": "Returns every device-settings document configured in the active company (used by the back-office to pick a layout to clone).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Settings documents"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/settings": {
      "get": {
        "operationId": "SettingsController_fetch",
        "summary": "Fetch settings by location",
        "description": "Returns the device-settings documents matching the given location ids.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Settings documents for the locations"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "SettingsController_create",
        "summary": "Create a device settings document",
        "description": "Creates a new device settings (layout, theme, terminal, features) for the active company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.Settings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created settings document"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "SettingsController_update",
        "summary": "Update a settings document",
        "description": "Partial update of an existing device settings document (any field except the identity).",
        "parameters": [
          {
            "name": "settingsId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9b0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.Settings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated settings document"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "SettingsController_delete",
        "summary": "Delete a settings document",
        "description": "Removes a device settings document from the caller company.",
        "parameters": [
          {
            "name": "settingsId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9b0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/settings/one": {
      "get": {
        "operationId": "SettingsController_fetchOne",
        "summary": "Fetch a settings document by id",
        "description": "Returns the full settings document for the given id.",
        "parameters": [
          {
            "name": "settingsId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9b0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Settings document"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/devices/settings/bulk-grid": {
      "patch": {
        "operationId": "SettingsController_bulkUpdateGrid",
        "summary": "Bulk-update the UI grid",
        "description": "Applies the same grid layout to several locations (and optionally specific settings ids) at once.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.BulkGridUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update result"
          }
        },
        "tags": [
          "Devices:Settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules": {
      "post": {
        "operationId": "SchedulesController_create",
        "summary": "Create a schedule",
        "description": "Creates a schedule that activates menus, offers or devices at specific weekly time windows.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateSchedule"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created schedule"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "SchedulesController_update",
        "summary": "Update a schedule",
        "description": "Partial update of a schedule owned by the caller company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateSchedule"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated schedule"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "SchedulesController_delete",
        "summary": "Delete a schedule",
        "description": "Removes the schedule owned by the caller company.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9a7",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/device": {
      "get": {
        "operationId": "SchedulesController_fetchDeviceSchedule",
        "summary": "Fetch schedules for a device",
        "description": "Returns the schedules active on the calling device, optionally filtered by type.",
        "parameters": [
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Schedule type filter (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedules for the device"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/endpoint": {
      "get": {
        "operationId": "SchedulesController_fetchEndpointSchedule",
        "summary": "Fetch schedules for an endpoint",
        "description": "Returns the schedules applicable to an endpoint session for a given location (and optional type).",
        "parameters": [
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Schedule type filter (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location id to fetch schedules for",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedules for the endpoint"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/endpoint/web": {
      "get": {
        "operationId": "SchedulesController_fetchEndpointScheduleWeb",
        "summary": "Fetch web endpoint schedules",
        "description": "Returns schedules for the web-specific variant of the endpoint (different rendering constraints than in-app).",
        "parameters": [
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Schedule type filter (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location id to fetch schedules for",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedules for the web endpoint"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/device/versions": {
      "get": {
        "operationId": "SchedulesController_fetchDeviceMenuVersions",
        "summary": "Fetch menu versions for a device",
        "description": "Lightweight list of { menuId, version } for the menus active on the calling device. Clients poll this to detect stale menus.",
        "parameters": [
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Schedule type filter (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Menu versions for the device"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/endpoint/web/versions": {
      "get": {
        "operationId": "SchedulesController_fetchEndpointMenuVersionsWeb",
        "summary": "Fetch web endpoint menu versions",
        "description": "Lightweight list of { menuId, version } for the menus of a web endpoint. Clients poll this to detect stale menus.",
        "parameters": [
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Schedule type filter (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location id to fetch schedules for",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Menu versions for the web endpoint"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/by-company": {
      "get": {
        "operationId": "SchedulesController_getSchedulesByCompany",
        "summary": "List schedules for the active company",
        "description": "Returns every schedule configured for the caller company across all locations.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Schedules for the company",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9a7",
                      "name": "Lunch menu",
                      "type": "MENU",
                      "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "days": {
                        "mon": [
                          {
                            "from": "12:00",
                            "to": "16:00"
                          }
                        ]
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/schedules/by-menu": {
      "get": {
        "operationId": "SchedulesController_getSchedulesByMenu",
        "summary": "List schedules targeting a menu",
        "description": "Returns every schedule that activates the given menu id, optionally scoped to a location/company.",
        "parameters": [
          {
            "name": "menuId",
            "required": true,
            "in": "query",
            "description": "Menu id whose schedules should be returned",
            "example": "64f1b8a2c3d4e5f6a7b8c9a8",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "description": "Location id to scope the query to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "companyId",
            "required": false,
            "in": "query",
            "description": "Company id to scope the query to",
            "example": "64f1b8a2c3d4e5f6a7b8c9c0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedules for the menu"
          }
        },
        "tags": [
          "Schedules"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks/done/device": {
      "post": {
        "operationId": "TasksDoneController_create",
        "summary": "Record a task completion from a device",
        "description": "Member-from-device endpoint to submit a completed task with its input responses and optional evidence.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateTaskDone"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored task completion record"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "TasksDoneController_fetchFromDevice",
        "summary": "List task completions for the calling device",
        "description": "Returns completions filed by members operating on the calling device, scoped to the device location.",
        "parameters": [
          {
            "name": "taskId",
            "required": true,
            "in": "query",
            "description": "Task template id",
            "example": "64f1b8a2c3d4e5f6a7b8c9e4",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "description": "Location id to filter by",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "Number of records to skip (pagination)",
            "example": "0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Maximum number of records to return (pagination)",
            "example": "20",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Task completion records"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks/done/push-response": {
      "post": {
        "operationId": "TasksDoneController_pushResponse",
        "summary": "Push an async response for a task",
        "description": "Used to append asynchronous results (e.g. an uploaded image URL that was processed later) to an existing task completion.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Async response payload",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "example": {
                  "taskDoneId": "64f1b8a2c3d4e5f6a7b8c9f5",
                  "input": "Before-photo",
                  "value": "https://cdn.platomico.com/tasks/done/before.jpg"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response appended"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks/done": {
      "get": {
        "operationId": "TasksDoneController_fetch",
        "summary": "List task completions",
        "description": "Returns task completion records filtered by task/location with pagination.",
        "parameters": [
          {
            "name": "taskId",
            "required": true,
            "in": "query",
            "description": "Task template id",
            "example": "64f1b8a2c3d4e5f6a7b8c9e4",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "description": "Location id to filter by",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "Number of records to skip (pagination)",
            "example": "0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Maximum number of records to return (pagination)",
            "example": "20",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Task completion records"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "TasksDoneController_update",
        "summary": "Update a task completion",
        "description": "Partial update for a task completion record (e.g. correct an input value).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Partial update payload",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "example": {
                  "id": "64f1b8a2c3d4e5f6a7b8c9f5",
                  "response": {
                    "inputs": [
                      {
                        "name": "Before-photo",
                        "value": "https://cdn.platomico.com/tasks/done/before.jpg"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated completion"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks/done/done-today": {
      "get": {
        "operationId": "TasksDoneController_fetchDoneToday",
        "summary": "List today's completions for a task",
        "description": "Returns the task completion records filed today at the calling member location for the given task id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9e4",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Today's completions"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks/done/location": {
      "get": {
        "operationId": "TasksDoneController_fetchLocationTasks",
        "summary": "List task completions at the member location",
        "description": "Returns completions filed at the calling member location for the given task id, paginated.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9e4",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "required": true,
            "in": "query",
            "example": 0,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": true,
            "in": "query",
            "example": 20,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Task completion records"
          }
        },
        "tags": [
          "Tasks:Done"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks": {
      "post": {
        "operationId": "TasksController_create",
        "summary": "Create a recurring task",
        "description": "Creates a recurring operations task (checklist style) with optional inputs and workflow events.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateTask"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created task"
          }
        },
        "tags": [
          "Tasks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "TasksController_fetch",
        "summary": "List tasks for a location",
        "description": "Returns every active task for the given location. Accepts the location id as a raw query string.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "Tasks at the location",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9e4",
                      "title": "Mop the kitchen floor",
                      "cooldown": 3600,
                      "inputs": [
                        {
                          "name": "Before-photo",
                          "type": "IMAGE",
                          "required": true
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Tasks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "TasksController_update",
        "summary": "Update a task",
        "description": "Partial update of a task (title, inputs, cooldown, active/visible flags).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateTask"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated task"
          }
        },
        "tags": [
          "Tasks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "TasksController_delete",
        "summary": "Delete a task",
        "description": "Permanently removes a task from the location.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.TaskId"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Tasks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/tasks/device": {
      "get": {
        "operationId": "TasksController_fetchDeviceTasks",
        "summary": "List tasks for the calling device member",
        "description": "Returns tasks active at the location bound to the calling member/device session.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Tasks for the member location"
          }
        },
        "tags": [
          "Tasks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members": {
      "get": {
        "operationId": "MembersController_fetch",
        "summary": "List members",
        "description": "Returns members belonging to the caller company, optionally filtered by location ids.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Members visible to the caller",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9e2",
                      "name": "Maria",
                      "lastName": "Gomez",
                      "role": "Manager",
                      "code": 482913,
                      "active": true
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "MembersController_create",
        "summary": "Create a member",
        "description": "Creates a new member for the active company and locations. An invitation email is sent when an email is provided.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.Member"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created member"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "MembersController_update",
        "summary": "Update a member",
        "description": "Partial update of a member record.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateMember"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated member"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "MembersController_remove",
        "summary": "Delete a member",
        "description": "Removes a member from the active company.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9e2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/one": {
      "get": {
        "operationId": "MembersController_fetchById",
        "summary": "Fetch a member by id",
        "description": "Returns the full member document for the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9e2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Member details"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/bulk": {
      "patch": {
        "operationId": "MembersController_bulkUpdateRole",
        "summary": "Bulk update member roles",
        "description": "Assigns the same role to every member in the provided list. Members that are missing or belong to another company are skipped and reported as failures.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.BulkUpdateRole"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-member result of the bulk role update",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "updated": [
                      "64f1b8a2c3d4e5f6a7b8c9e2"
                    ],
                    "failed": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9e3",
                        "reason": "Member not found"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/activate": {
      "patch": {
        "operationId": "MembersController_activate",
        "summary": "Activate a member",
        "description": "Marks a member as active so that their pin code can be used to sign in on a device.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "memberId"
                ],
                "properties": {
                  "memberId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e2"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Activation result"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/resend": {
      "post": {
        "operationId": "MembersController_resend",
        "summary": "Resend a member invitation",
        "description": "Re-sends the member invitation email (used when the original one was lost or expired).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "memberId"
                ],
                "properties": {
                  "memberId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9e2"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invitation dispatched"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/verify": {
      "post": {
        "operationId": "MembersController_verify",
        "summary": "Verify a member's email code",
        "description": "Validates the numeric code sent to the member email as part of invitation completion.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "code"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "example": "maria@tacosplatomico.com"
                  },
                  "code": {
                    "type": "number",
                    "example": 482913
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification result"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/onboard/complete": {
      "post": {
        "operationId": "MembersController_completeOnboard",
        "summary": "Complete member onboarding via magic link",
        "description": "Public endpoint. Redeems the single-use magic-link key from the staff invitation email and returns a persistent member session token for the paired phone.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "example": "lyq3k2f8a1b2c3d4"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Granted member session"
          }
        },
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/timeclock/qr-token": {
      "get": {
        "operationId": "TimeclockController_qrToken",
        "summary": "Mint a rotating clock-in QR token",
        "description": "Device-authed. Returns a short-lived signed JWT { locationId, companyId, from, to } for the POS to render as a rotating QR. Members scan it to clock in/out.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Signed QR token and its validity window"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/timeclock/config": {
      "get": {
        "operationId": "TimeclockController_config",
        "summary": "Clock methods enabled for the caller company",
        "description": "Device-authed. Returns { clockByQrEnabled, clockByPinEnabled } with defaults applied (QR on unless disabled, PIN off unless enabled) so the POS knows which clock methods to render.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Enabled clock methods"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/timeclock/clock-by-code": {
      "post": {
        "operationId": "TimeclockController_clockByCode",
        "summary": "Clock a member in/out by PIN code on the device",
        "description": "Device-authed. Resolves the member by (company, code) within the device location scope and toggles their clock session. Rejects with PIN_CLOCK_DISABLED when clockByPinEnabled is not on, MEMBER_NOT_FOUND when no member matches.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ClockByCodeDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Clock receipt { type, memberName, clock }"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/timeclock": {
      "get": {
        "operationId": "TimeclockController_list",
        "summary": "List member clock sessions",
        "description": "Returns clock sessions within the [from,to] range for the caller company, optionally filtered by location.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-06-30T23:59:59.999Z",
            "schema": {}
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-06-01T00:00:00.000Z",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "Clock sessions in range"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/me/shift/today": {
      "get": {
        "operationId": "TimeclockController_shiftToday",
        "summary": "Resolve the caller member's shift for a day",
        "description": "Member-token self endpoint. Resolves the caller's scheduled segments (with breaks) for the given date in the company timezone, defaulting to today. off:true when free/absent/day-off.",
        "parameters": [
          {
            "name": "date",
            "required": false,
            "in": "query",
            "example": "2026-06-29",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved shift for the day"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/{memberId}/timeclock/clock-in": {
      "post": {
        "operationId": "TimeclockController_clockIn",
        "summary": "Clock a member in",
        "description": "Opens an ACTIVE clock session for the member. Rejects with ALREADY_CLOCKED_IN if one is already open.",
        "parameters": [
          {
            "name": "memberId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9e2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ClockInDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Opened clock session"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/{memberId}/timeclock/clock-out": {
      "post": {
        "operationId": "TimeclockController_clockOut",
        "summary": "Clock a member out",
        "description": "Closes the ACTIVE clock session (sets out + elapsed). No active session is a no-op 200.",
        "parameters": [
          {
            "name": "memberId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9e2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.ClockOutDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Closed clock session, or no-op when none active"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/{memberId}/timeclock/status": {
      "get": {
        "operationId": "TimeclockController_status",
        "summary": "Member clock status",
        "description": "Returns whether the member currently has an ACTIVE session.",
        "parameters": [
          {
            "name": "memberId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9e2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current clock status"
          }
        },
        "tags": [
          "Members Timeclock"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/members/attendance": {
      "get": {
        "operationId": "AttendanceController_attendance",
        "summary": "Member attendance report",
        "description": "Crosses scheduled member shifts with clock sessions over [from,to] for the caller company: presences, no-shows (absences), late arrivals, worked vs assigned minutes, presenteeism. Days covered by a ShiftAbsence are excluded.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "schema": {}
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-06-30",
            "schema": {}
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-06-01",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "Attendance report for members in scope"
          }
        },
        "tags": [
          "Members Attendance"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/shifts/templates": {
      "post": {
        "operationId": "ShiftsController_createShiftTemplate",
        "summary": "Create a shift template for the current company",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateShiftTemplateDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "get": {
        "operationId": "ShiftsController_fetchShiftTemplates",
        "summary": "Fetch shift templates for the current company",
        "parameters": [
          {
            "name": "archived",
            "required": false,
            "in": "query",
            "description": "Include archived (visible:false) templates",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/templates/{templateId}": {
      "patch": {
        "operationId": "ShiftsController_updateShiftTemplate",
        "summary": "Update a shift template",
        "parameters": [
          {
            "name": "templateId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateShiftTemplateDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "delete": {
        "operationId": "ShiftsController_deleteShiftTemplate",
        "summary": "Archive a shift template (default), or purge it permanently with ?purge=true when unused",
        "parameters": [
          {
            "name": "templateId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "purge",
            "required": false,
            "in": "query",
            "description": "Permanently delete (only allowed when usage is 0)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/templates/{templateId}/usage": {
      "get": {
        "operationId": "ShiftsController_fetchShiftTemplateUsage",
        "summary": "List user IDs whose shifts reference this template",
        "parameters": [
          {
            "name": "templateId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/templates/{templateId}/restore": {
      "post": {
        "operationId": "ShiftsController_restoreShiftTemplate",
        "summary": "Restore an archived shift template",
        "parameters": [
          {
            "name": "templateId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/absences": {
      "post": {
        "operationId": "ShiftsController_createShiftAbsence",
        "summary": "Create an absence",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateShiftAbsenceDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "get": {
        "operationId": "ShiftsController_fetchShiftAbsences",
        "summary": "Fetch absences for the current company",
        "parameters": [
          {
            "name": "userId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/absences/{absenceId}": {
      "patch": {
        "operationId": "ShiftsController_updateShiftAbsence",
        "summary": "Update an absence",
        "parameters": [
          {
            "name": "absenceId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateShiftAbsenceDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "delete": {
        "operationId": "ShiftsController_deleteShiftAbsence",
        "summary": "Delete an absence",
        "parameters": [
          {
            "name": "absenceId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/requests": {
      "get": {
        "operationId": "ShiftsController_fetchRequests",
        "summary": "Fetch absence requests for the current company",
        "parameters": [
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {}
          },
          {
            "name": "userType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/requests/paged": {
      "get": {
        "operationId": "ShiftsController_fetchRequestsPage",
        "summary": "List a page of absence requests with the matching total",
        "description": "Same filter and ordering as the list endpoint, narrowed to one page and paired with the total matching that filter. Omitting `limit` returns everything, exactly as the list endpoint does.",
        "parameters": [
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "example": "20",
            "schema": {}
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "example": "0",
            "schema": {}
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {}
          },
          {
            "name": "userType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/requests/count": {
      "get": {
        "operationId": "ShiftsController_countRequests",
        "summary": "Count absence requests matching the filter",
        "description": "Returns only the number of matching requests. Same filter as the list endpoint, for callers that render a count and never the rows.",
        "parameters": [
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {}
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {}
          },
          {
            "name": "userType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/requests/{requestId}": {
      "patch": {
        "operationId": "ShiftsController_decideRequest",
        "summary": "Approve or reject an absence request",
        "parameters": [
          {
            "name": "requestId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.DecideRequestDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/resolve": {
      "get": {
        "operationId": "ShiftsController_resolveAllShiftsRange",
        "summary": "Resolve all shifts for a date range (bulk)",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          },
          {
            "name": "fleetId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts": {
      "post": {
        "operationId": "ShiftsController_createShift",
        "summary": "Create a shift for the current company",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateShiftDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "get": {
        "operationId": "ShiftsController_fetchShifts",
        "summary": "Fetch shifts for the current company",
        "parameters": [
          {
            "name": "userType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          },
          {
            "name": "fleetId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/{shiftId}": {
      "get": {
        "operationId": "ShiftsController_fetchShift",
        "summary": "Fetch a single shift by id",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "patch": {
        "operationId": "ShiftsController_updateShift",
        "summary": "Update a shift",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateShiftDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "delete": {
        "operationId": "ShiftsController_deleteShift",
        "summary": "Delete (soft) a shift",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/{shiftId}/resolve": {
      "get": {
        "operationId": "ShiftsController_resolveShiftRange",
        "summary": "Resolve a shift to a day-by-day expansion over a date range",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/{shiftId}/overrides": {
      "post": {
        "operationId": "ShiftsController_createShiftOverride",
        "summary": "Create or upsert a date override for a shift",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateShiftOverrideDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "get": {
        "operationId": "ShiftsController_fetchShiftOverrides",
        "summary": "Fetch date overrides for a shift",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/{shiftId}/overrides/{overrideId}": {
      "patch": {
        "operationId": "ShiftsController_updateShiftOverride",
        "summary": "Update a shift date override",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overrideId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateShiftOverrideDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "delete": {
        "operationId": "ShiftsController_deleteShiftOverride",
        "summary": "Delete a shift date override",
        "parameters": [
          {
            "name": "shiftId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overrideId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/shifts/by-user/{userId}": {
      "get": {
        "operationId": "ShiftsController_fetchShiftsForUser",
        "summary": "Fetch shifts assigned to a user",
        "parameters": [
          {
            "name": "userId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userType",
            "required": true,
            "in": "query",
            "schema": {
              "enum": [
                "member",
                "courier"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Shifts"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/members/me/absence-requests": {
      "post": {
        "operationId": "MemberAbsenceRequestsController_create",
        "summary": "Create an absence request for the caller member",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateAbsenceRequestDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Member Absence Requests"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "get": {
        "operationId": "MemberAbsenceRequestsController_list",
        "summary": "List the caller member's absence requests",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Member Absence Requests"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/members/me/absence-requests/{requestId}": {
      "delete": {
        "operationId": "MemberAbsenceRequestsController_cancel",
        "summary": "Cancel a pending absence request",
        "parameters": [
          {
            "name": "requestId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Member Absence Requests"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/loyalty/programs": {
      "post": {
        "operationId": "ProgramsController_create",
        "summary": "Create a loyalty program",
        "description": "Creates a new loyalty program (stamps, points, tiered) for the active company and its locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateProgram"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created program"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "ProgramsController_fetch",
        "summary": "List loyalty programs",
        "description": "Returns every loyalty program visible to the signed-in user.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Loyalty programs",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9b5",
                      "name": "Coffee lovers",
                      "type": "STAMPS",
                      "active": true
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ProgramsController_update",
        "summary": "Update a loyalty program",
        "description": "Partial update of a loyalty program owned by the caller company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Updated program"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ProgramsController_delete",
        "summary": "Delete a loyalty program",
        "description": "Removes a loyalty program owned by the caller company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/reward": {
      "post": {
        "operationId": "ProgramsController_createReward",
        "summary": "Create a loyalty reward",
        "description": "Attaches a reward (free item or discount) to an existing program. Customers earn these when they reach program milestones.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.createReward"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created reward"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/benefits": {
      "post": {
        "operationId": "BenefitsController_create",
        "summary": "Create a loyalty benefit",
        "description": "Attaches a benefit (discounted or free item/meal/discount) to a loyalty program, with redemption constraints (auto-apply, quotas, time window).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateBenefit"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created benefit"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/templates": {
      "post": {
        "operationId": "TemplatesController_create",
        "summary": "Create a wallet template",
        "description": "Creates a Google/Apple Wallet template (style + fields) bound to a loyalty program and color palette.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateTemplate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created template"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "TemplatesController_fetch",
        "summary": "List templates",
        "description": "Returns templates visible to the signed-in user. (WIP stub)",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Templates"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "TemplatesController_update",
        "summary": "Update a template",
        "description": "Partial update of a loyalty template owned by the caller company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Updated template"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "TemplatesController_delete",
        "summary": "Delete a template",
        "description": "Removes a loyalty template owned by the caller company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/templates/endpoint": {
      "get": {
        "operationId": "TemplatesController_fetchFromEndpoint",
        "summary": "Fetch a template from an endpoint",
        "description": "Returns the wallet template for a (program, template) pair, called from an embedded endpoint.",
        "parameters": [
          {
            "name": "pid",
            "required": true,
            "in": "query",
            "description": "Program id",
            "example": "64f1b8a2c3d4e5f6a7b8c9b5",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tid",
            "required": true,
            "in": "query",
            "description": "Template id",
            "example": "64f1b8a2c3d4e5f6a7b8c9b6",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template details"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/templates/device": {
      "get": {
        "operationId": "TemplatesController_fetchFromDevice",
        "summary": "Fetch templates for a device",
        "description": "Returns every template available to the calling device (used to preview passes before printing).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Templates"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/templates/colors": {
      "get": {
        "operationId": "TemplatesController_fetchColors",
        "summary": "List wallet color palettes",
        "description": "Returns wallet color palettes available for the given locations.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Locations to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Color palettes",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9b7",
                      "name": "Platomico orange",
                      "hex": "#FF6600"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/passes/endpoint": {
      "get": {
        "operationId": "PassesController_fetchFromEndpoint",
        "summary": "Fetch a customer pass from an endpoint",
        "description": "Returns the calling customer pass for the given program id, as seen from an embedded endpoint (ordering/QR).",
        "parameters": [
          {
            "name": "pid",
            "required": true,
            "in": "query",
            "description": "Loyalty program id",
            "example": "64f1b8a2c3d4e5f6a7b8c9b5",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pass details for the customer",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "passId": "64f1b8a2c3d4e5f6a7b8c9b8",
                    "programId": "64f1b8a2c3d4e5f6a7b8c9b5",
                    "stamps": 6,
                    "goal": 10
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/passes/device": {
      "get": {
        "operationId": "PassesController_fetchFromDevice",
        "summary": "Fetch a pass from a device",
        "description": "Returns the pass details used by a device (e.g. POS) to render loyalty state for the scanned customer.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Pass id",
            "example": "64f1b8a2c3d4e5f6a7b8c9b8",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pass details"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "PassesController_logoutFromDevice",
        "summary": "Log a pass out from a device",
        "description": "Detaches the currently-scanned pass from the device session, returning the device to the neutral state.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Pass id",
            "example": "64f1b8a2c3d4e5f6a7b8c9b8",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Logout acknowledged"
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/loyalty/programs/passes/join": {
      "get": {
        "operationId": "PassesController_join",
        "summary": "Join a loyalty program",
        "description": "Customer endpoint to join a program and receive a wallet pass (Apple or Google) bound to the chosen template.",
        "parameters": [
          {
            "name": "programId",
            "required": true,
            "in": "query",
            "description": "Loyalty program to join",
            "example": "64f1b8a2c3d4e5f6a7b8c9b5",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "templateId",
            "required": true,
            "in": "query",
            "description": "Template used for the generated wallet pass",
            "example": "64f1b8a2c3d4e5f6a7b8c9b6",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "Wallet provider the pass should be generated for",
            "example": "apple",
            "schema": {
              "enum": [
                "apple",
                "google"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Generated pass + wallet install link",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "passId": "64f1b8a2c3d4e5f6a7b8c9b8",
                    "installUrl": "https://wallet.google.com/save/abc123"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/ernesto/audits/types": {
      "get": {
        "operationId": "AuditsController_fetchTypes",
        "summary": "List available audit types",
        "description": "Returns every audit template (cleanliness, opening checklist, etc.) available to the member. Used by the dashboard to build the audit picker.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Available audit types with their questions",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9a1",
                      "name": "Opening checklist",
                      "version": 2,
                      "active": true,
                      "questions": [
                        {
                          "id": "64f1b8a2c3d4e5f6a7b8c9b1",
                          "text": "Is the cash drawer balanced?",
                          "answerType": "CHOICE",
                          "photoRequired": false
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/ernesto/audits/types/{identifier}": {
      "get": {
        "operationId": "AuditsController_fetchTypeByIdentifier",
        "summary": "Fetch an audit type by identifier",
        "description": "Returns the full definition (questions, choices, photo requirements) for a single audit type.",
        "parameters": [
          {
            "name": "identifier",
            "required": true,
            "in": "path",
            "example": "cleanliness",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full audit type definition",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9a1",
                    "name": "Cleanliness",
                    "version": 3,
                    "active": true,
                    "questions": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9b1",
                        "text": "Is the kitchen floor clean?",
                        "answerType": "CHOICE",
                        "photoRequired": true
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/ernesto/audits": {
      "post": {
        "operationId": "AuditsController_createAudit",
        "summary": "Submit an audit response",
        "description": "Records the member responses for one audit run. Can be saved as a draft (draft: true) and finalized later.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateAuditResponse"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored audit response",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9c1",
                    "type": "cleanliness",
                    "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "draft": false,
                    "createdAt": "2026-04-23T12:00:00.000Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "AuditsController_fetchAudits",
        "summary": "List audits for a location",
        "description": "Returns the most recent audit responses filed at the given location, sorted most-recent-first.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audits recorded at the location",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9c1",
                      "type": "cleanliness",
                      "author": {
                        "userId": "64f1b8a2c3d4e5f6a7b8c9e2",
                        "role": "Manager"
                      },
                      "createdAt": "2026-04-23T12:00:00.000Z"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/ernesto/audits/{identifier}": {
      "get": {
        "operationId": "AuditsController_fetchAuditByIdentifier",
        "summary": "Fetch an audit response by identifier",
        "description": "Returns the full audit response (questions, answers, images) for the given identifier.",
        "parameters": [
          {
            "name": "identifier",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9c1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit response details",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9c1",
                    "type": "cleanliness",
                    "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "items": [
                      {
                        "questionId": "64f1b8a2c3d4e5f6a7b8c9b1",
                        "question": "Is the kitchen floor clean?",
                        "choice": "YES",
                        "answer": null
                      }
                    ],
                    "createdAt": "2026-04-23T12:00:00.000Z"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/subscribers": {
      "get": {
        "operationId": "SubscribersController_fetchPaginated",
        "summary": "List subscribers (paginated)",
        "description": "Returns newsletter/marketing subscribers for the active company, with optional text search, status filter and createdAt range.",
        "parameters": [
          {
            "name": "createdAtTo",
            "required": false,
            "in": "query",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {}
          },
          {
            "name": "createdAtFrom",
            "required": false,
            "in": "query",
            "example": "2026-01-01T00:00:00.000Z",
            "schema": {}
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "example": "ACTIVE",
            "schema": {}
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "example": "maria",
            "schema": {}
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "example": "10",
            "schema": {}
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "example": "1",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated subscribers",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "items": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9e3",
                        "email": "maria@example.com",
                        "status": "ACTIVE",
                        "createdAt": "2026-04-10T12:00:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "pageSize": 10
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Subscribers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints": {
      "post": {
        "operationId": "EndpointsController_create",
        "summary": "Create an endpoint",
        "description": "Creates a new endpoint (embedded ordering/QR site) with its branding and domain bindings for the active company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateEndpoint"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created endpoint"
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints/by-company": {
      "get": {
        "operationId": "EndpointsController_fetchByCompany",
        "summary": "List endpoints for the active company",
        "description": "Returns every endpoint configured for the caller company, with their domains and settings.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Endpoints for the company",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9f1",
                      "name": "Tacos Platomico Order Online",
                      "domains": [
                        "order.tacosplatomico.com"
                      ],
                      "scopes": [
                        "ORDER"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints/{endpointId}": {
      "patch": {
        "operationId": "EndpointsController_update",
        "summary": "Update the identity of an endpoint",
        "description": "Renames an endpoint, sets which frontend it backs and which locations it serves. Only the fields sent are written. Branding lives on PATCH /:endpointId/settings and domains on PATCH /:endpointId/domains — this route touches neither. Scoped to the caller company.",
        "parameters": [
          {
            "name": "endpointId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9f1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateEndpoint"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated endpoint"
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints/{endpointId}/domains": {
      "patch": {
        "operationId": "EndpointsController_updateDomains",
        "summary": "Replace the ordered domains of an endpoint",
        "description": "Replaces the endpoint domain list with the array sent. Index 0 is the DEFAULT domain, so reordering is how the default is chosen — one call covers adding, removing, reordering and setting the default. Scoped to the caller company.",
        "parameters": [
          {
            "name": "endpointId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9f1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateEndpointDomains"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated endpoint"
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints/{endpointId}/settings": {
      "patch": {
        "operationId": "EndpointsController_updateSettings",
        "summary": "Update the branding and style overrides of an endpoint",
        "description": "Writes the customization studio output onto an endpoint. `ui` is shallow-merged (so a save that carries only `override` keeps `pageThemes` and `itemPalettes`); brand tokens are assigned wholesale. Base64 assets in `image`/`fontFiles`/`uiImages` are uploaded to S3 and replaced by their URLs. Scoped to the caller company. There is no push channel to a browser, so the change applies on the visitor next page load.",
        "parameters": [
          {
            "name": "endpointId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9f1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateEndpointSettings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated endpoint"
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints/seo": {
      "get": {
        "operationId": "EndpointsController_fetchSeoByDomain",
        "summary": "Fetch SEO metadata by domain",
        "description": "Public endpoint used by server-side rendered frontends to bootstrap page title/description/og image for a given domain.",
        "parameters": [
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "example": "order.tacosplatomico.com",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SEO metadata for the domain",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "title": "Tacos Platomico - Order Online",
                    "description": "Order delicious tacos online",
                    "image": "https://cdn.platomico.com/seo/tacos.jpg"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/endpoints/provider": {
      "get": {
        "operationId": "EndpointsController_fetchProviderByDomain",
        "summary": "Fetch provider configuration by domain",
        "description": "Returns terminal/online/delivery provider configuration for the endpoint matching the given domain. Used by the embedded checkout to pick SDKs.",
        "parameters": [
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "example": "order.tacosplatomico.com",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Provider configuration",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "terminal": {
                      "provider": "STRIPE",
                      "version": 2
                    },
                    "online": {
                      "provider": "STRIPE"
                    },
                    "delivery": {
                      "provider": "CATCHER",
                      "version": 1
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Endpoints"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/onboarding/progress": {
      "get": {
        "operationId": "OnboardingController_readProgress",
        "summary": "Read onboarding progress",
        "description": "Returns the saved onboarding wizard progress for the authenticated user, or null if none exists.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Saved onboarding progress or null"
          }
        },
        "tags": [
          "Onboarding"
        ]
      },
      "put": {
        "operationId": "OnboardingController_upsertProgress",
        "summary": "Upsert onboarding progress",
        "description": "Idempotent whole-object upsert of the onboarding wizard progress for the authenticated user.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.OnboardingProgressDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored onboarding progress"
          }
        },
        "tags": [
          "Onboarding"
        ]
      }
    },
    "/operations/onboarding": {
      "post": {
        "operationId": "OnboardingController_getMenu",
        "summary": "Scrape a menu during onboarding",
        "description": "Given a Google Places business and a viewport width, scrapes the business reviews/menus and returns a draft menu. Called during signup to prefill the catalog.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Onboarding scrape payload",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "companyInfo",
                  "sessionId",
                  "width"
                ],
                "properties": {
                  "companyInfo": {
                    "type": "object",
                    "example": {
                      "name": "Tacos Platomico",
                      "place_id": "ChIJyWEHuEmuEmsRm9hTkapTCrk"
                    }
                  },
                  "sessionId": {
                    "type": "string",
                    "example": "onb_sess_abc123"
                  },
                  "width": {
                    "type": "number",
                    "example": 1280
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scraped menu and side data",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "menu": {
                      "categories": [
                        {
                          "name": "Tacos",
                          "items": [
                            {
                              "name": "Carnitas Taco",
                              "price": 250
                            }
                          ]
                        }
                      ]
                    },
                    "reviews": [
                      {
                        "author": "Maria G.",
                        "rating": 5,
                        "text": "Best tacos in Madrid!"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Onboarding"
        ]
      }
    },
    "/operations/preferences/channel-groups": {
      "get": {
        "operationId": "ChannelGroupsPreferenceController_fetch",
        "summary": "Fetch the caller channel-groups preference",
        "description": "Returns the caller channel-groups preference, scoped per company. Falls back to an empty preference when none has been stored yet.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Channel groups preference for the caller",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/operations.ChannelGroupsPreferenceResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "put": {
        "operationId": "ChannelGroupsPreferenceController_upsert",
        "summary": "Upsert the caller channel-groups preference",
        "description": "Replaces the full preference document for the caller in the active company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.UpdateChannelGroupsPreference"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persisted channel groups preference",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/operations.ChannelGroupsPreferenceResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Preferences"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/operations/incidents": {
      "get": {
        "operationId": "IncidentsController_list",
        "summary": "List incidents for current company",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Incidents"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      },
      "post": {
        "operationId": "IncidentsController_create",
        "summary": "Create an incident for current company",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/operations.CreateIncidentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Incidents"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/incidents/{incidentId}": {
      "get": {
        "operationId": "IncidentsController_detail",
        "summary": "Fetch a single incident by id",
        "parameters": [
          {
            "name": "incidentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Incidents"
        ],
        "security": [
          {
            "Authorization": []
          }
        ]
      }
    },
    "/operations/releases/latest": {
      "get": {
        "operationId": "ReleasesController_fetchLatest",
        "summary": "Fetch the newest published build for an app",
        "description": "Called by a device to decide whether to install a newer APK over itself. Returns null when nothing is published for the applicationId + channel.",
        "parameters": [
          {
            "name": "applicationId",
            "required": true,
            "in": "query",
            "description": "Android applicationId the calling device is running",
            "example": "kitchen.platomico.com",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel",
            "required": false,
            "in": "query",
            "description": "Release channel, defaults to production",
            "example": "production",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The newest release, or null",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "applicationId": "kitchen.platomico.com",
                    "channel": "production",
                    "versionName": "1.4.2",
                    "versionCode": 312,
                    "url": "https://expo.dev/artifacts/eas/abc123.apk"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Releases"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person": {
      "post": {
        "operationId": "PaymentsController_processInPersonPayment",
        "summary": "Process an in-person card payment (legacy)",
        "description": "Legacy single-step in-person card payment. Charges the reader paired to the calling device. Prefer the v2 endpoint for new integrations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction and payment result"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "PaymentsController_cancelInPersonPayment",
        "summary": "Cancel an in-flight in-person payment (legacy)",
        "description": "Cancels the pending in-person payment currently attached to the calling device.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Cancellation result"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/token": {
      "post": {
        "operationId": "PaymentsController_createInPersonPaymentToken",
        "summary": "Create a token for an in-person payment (legacy)",
        "description": "Creates an intent/token for a card payment that will be finalised in a separate step (useful to split UI flows).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token reference",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "token": "tok_1NVf4HKj8i9s3xYz"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/with-token": {
      "post": {
        "operationId": "PaymentsController_processInPersonPaymentWithToken",
        "summary": "Finalise an in-person payment using a token (legacy)",
        "description": "Processes an in-person payment using a token previously created via /in-person/token.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction and payment result"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/splitted/token": {
      "post": {
        "operationId": "PaymentsController_createInPersonPaymentSplittedToken",
        "summary": "Create a token for a split in-person payment (legacy)",
        "description": "Creates a token for a split payment (multiple cards/cash) that will be finalised in subsequent steps.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token reference",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "token": "tok_split_1NVf4HKj8i9s3xYz"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/splitted": {
      "post": {
        "operationId": "PaymentsController_processInPersonSplittedPayment",
        "summary": "Process a single leg of a split in-person payment (legacy)",
        "description": "Charges one leg (card/cash portion) of a previously tokenised split payment.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-leg transaction result"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/splitted/refund": {
      "post": {
        "operationId": "PaymentsController_processInPersonSplittedPaymentRefund",
        "summary": "Refund a split in-person payment (legacy)",
        "description": "Refunds a split in-person payment leg or the full operation.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Refund result"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/with-cash": {
      "post": {
        "operationId": "PaymentsController_processInPersonPaymentWithCash",
        "summary": "Process an in-person cash payment (legacy)",
        "description": "Records an in-person cash payment and computes change based on the tendered amount.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction result with change calculation"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/in-person/with-cash/intent": {
      "post": {
        "operationId": "PaymentsController_createInPersonCashPaymentIntent",
        "summary": "Create an in-person cash payment intent (legacy)",
        "description": "Creates a cash payment intent that can be completed or cancelled later.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cash payment intent"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/online/with-card": {
      "post": {
        "operationId": "PaymentsController_processOnlinePaymentWithCard",
        "summary": "Process an online card payment (legacy)",
        "description": "Charges a card for an online endpoint session (ordering site / QR). Legacy flow.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.PaymentWithCard"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction and payment result"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/online/validate-merchant": {
      "post": {
        "operationId": "PaymentsController_validateMerchant",
        "summary": "Validate the merchant for Apple Pay (legacy)",
        "description": "Returns the Apple Pay merchant session payload required to bootstrap the browser's Payment Request.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.ValidateMerchantPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Apple Pay merchant session"
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/online/intent": {
      "post": {
        "operationId": "PaymentsController_createPaymentIntent",
        "summary": "Create an online payment intent (legacy)",
        "description": "Creates a Stripe/Revolut payment intent for an online endpoint session, which the frontend then confirms.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.PaymentWithCard"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment intent client secret and metadata",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "clientSecret": "pi_1NVf4HKj8i9s3xYz_secret_abc",
                    "id": "pi_1NVf4HKj8i9s3xYz"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions": {
      "get": {
        "operationId": "TransactionsController_fetch",
        "summary": "List transactions (legacy)",
        "description": "Legacy transactions listing endpoint. Prefer /transactions/v2 for new integrations.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of transactions for the date range",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "amount": 1250,
                      "currency": "EUR",
                      "createdAt": "2026-04-23T12:00:00.000Z"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/endpoint": {
      "get": {
        "operationId": "TransactionsController_fetchFromEndpoint",
        "summary": "Fetch a transaction from an endpoint (legacy)",
        "description": "Returns a transaction for a customer-facing endpoint (QR, ordering). Lookup by transaction id or order id.",
        "parameters": [
          {
            "name": "tid",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "oid",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction details"
          }
        },
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/sources": {
      "post": {
        "operationId": "SourcesController_create",
        "summary": "Create a payment source",
        "description": "Registers a new origin/channel (e.g. a delivery provider store) so transactions coming from it can be attributed to the company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateSource"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created source record",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "externalId": "glovo_store_42",
                    "name": "Glovo - Sol store"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:Sources"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts": {
      "post": {
        "operationId": "DiscountsController_create",
        "summary": "Create a discount",
        "description": "Creates a new discount (percentage or fixed) with an optional set of redemption codes.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateDiscount"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created discount record",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "name": "Student 10% Off",
                    "type": "PERCENT",
                    "amount": 1000
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "DiscountsController_fetch",
        "summary": "List active discounts",
        "description": "Returns the active discounts for the given locations filtered by the caller source (POS, kiosk, etc.).",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of active discount records"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts/all": {
      "get": {
        "operationId": "DiscountsController_fetchAll",
        "summary": "List all discounts (including inactive)",
        "description": "Returns every discount configured for the given locations, including inactive/archived ones.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of discount records"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts/with-code": {
      "get": {
        "operationId": "DiscountsController_fetchByCode",
        "summary": "Find a discount by redemption code",
        "description": "Used by checkout to resolve a customer-entered discount code to a discount record.",
        "parameters": [
          {
            "name": "code",
            "required": true,
            "in": "query",
            "example": "STUDENT10",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "orderAmount",
            "required": false,
            "in": "query",
            "example": 1250,
            "description": "Current pre-discount cart total in cents; enables the minimum-order check (F6).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching discount record or null if not found"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts/by-id/{id}": {
      "get": {
        "operationId": "DiscountsController_fetchById",
        "summary": "Fetch a discount by id",
        "description": "Returns a single discount scoped to the session location, if applicable.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "orderAmount",
            "required": false,
            "in": "query",
            "example": 1250,
            "description": "Current pre-discount cart total in cents; enables the minimum-order check (F6).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Discount record"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts/device/count": {
      "get": {
        "operationId": "DiscountsController_countFromDevice",
        "summary": "Count discounts visible from a device",
        "description": "Returns the number of discounts available for the device session. Useful to show a badge in the POS.",
        "parameters": [
          {
            "name": "loyaltyCustomerId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Number of discounts",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "count": 7
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts/device": {
      "get": {
        "operationId": "DiscountsController_fetchFromDevice",
        "summary": "Fetch discounts for a device",
        "description": "Returns discounts resolved for the device session, optionally filtered by a specific set of ids.",
        "parameters": [
          {
            "name": "discountsIds",
            "required": true,
            "in": "query",
            "description": "Discount ids to fetch",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "loyaltyCustomerId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of discount records"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/discounts/{id}": {
      "patch": {
        "operationId": "DiscountsController_update",
        "summary": "Update a discount",
        "description": "Partially updates a discount (amount, scope, codes, etc.).",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.UpdateDiscount"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated discount record"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "DiscountsController_remove",
        "summary": "Delete a discount",
        "description": "Permanently removes a discount from the company.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/taxes": {
      "post": {
        "operationId": "TaxesController_create",
        "summary": "Create a tax rule",
        "description": "Registers a new tax (e.g. VAT) that will be applied to transactions matching its location scope.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateTax"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created tax record",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "name": "IVA 10%",
                    "type": "PERCENT",
                    "amount": 1000,
                    "currency": "EUR"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Taxes"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "TaxesController_fetch",
        "summary": "List taxes for locations",
        "description": "Returns the taxes configured for the given locations within the caller company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of tax records",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "IVA 10%",
                      "type": "PERCENT",
                      "amount": 1000,
                      "currency": "EUR"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Taxes"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "TaxesController_update",
        "summary": "Update a tax rule",
        "description": "Partially updates an existing tax record (amount, scope, name, etc.).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.UpdateTax"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated tax record"
          }
        },
        "tags": [
          "Taxes"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/fees": {
      "post": {
        "operationId": "FeesController_create",
        "summary": "Create a fee rule",
        "description": "Registers a new fee (e.g. delivery commission, service fee) that applies to transactions matching its location and provider scope.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateFee"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created fee record",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "name": "Delivery Service Fee",
                    "type": "PERCENT",
                    "amount": 3000
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Fees"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "FeesController_fetch",
        "summary": "List fees for locations",
        "description": "Returns the fees configured for the given locations within the caller company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of fee records",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Delivery Service Fee",
                      "type": "PERCENT",
                      "amount": 3000
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Fees"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "FeesController_update",
        "summary": "Update a fee rule",
        "description": "Replaces the stored values for an existing fee record (amount, scope, provider).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.UpdateFee"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated fee record"
          }
        },
        "tags": [
          "Fees"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers": {
      "get": {
        "operationId": "CashRegistersController_fetchCashRegisters",
        "summary": "List cash registers for the caller",
        "description": "Returns the cash registers visible to the caller, optionally filtered by one or more location ids.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "One or more location ids (repeat the parameter for multiple values)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "List of cash registers"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "CashRegistersController_create",
        "summary": "Create a cash register",
        "description": "Registers a new cash register for the given location and attaches it to one or more devices.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateCashRegister"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created cash register record",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "locationId": "64f1b8a2c3d4e5f6a7b8c9d1",
                    "devicesIds": [
                      "64f1b8a2c3d4e5f6a7b8c9d2"
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/device": {
      "get": {
        "operationId": "CashRegistersController_fetchFromDevice",
        "summary": "Fetch the cash register bound to the caller device",
        "description": "Returns the single cash register the calling device is attached to (if any).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Cash register bound to the device"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/open": {
      "post": {
        "operationId": "CashRegistersController_open",
        "summary": "Open the cash register for a shift",
        "description": "Records the starting float and marks the cash register open for the calling member.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.OpenCashRegister"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Opened snapshot record"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/close": {
      "post": {
        "operationId": "CashRegistersController_close",
        "summary": "Close the cash register shift",
        "description": "Closes the current shift, records the final counted cash, and produces a snapshot with any over/short difference.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CloseCashRegister"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Closed snapshot record"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/track": {
      "post": {
        "operationId": "CashRegistersController_track",
        "summary": "Track a cash movement",
        "description": "Records a single cash movement (sale, refund, income, outcome, change, etc.) against the caller cash register.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.TrackCashRegisterTransaction"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recorded cash transaction"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/balance": {
      "get": {
        "operationId": "CashRegistersController_fetchBalance",
        "summary": "Get the current cash balance",
        "description": "Returns the expected cash amount currently in the drawer for the specified register.",
        "parameters": [
          {
            "name": "registerId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current cash balance",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "amount": 15250,
                    "currency": "EUR"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/transactions": {
      "get": {
        "operationId": "CashRegistersController_fetchTransactions",
        "summary": "List cash register transactions",
        "description": "Returns cash movements recorded for the caller register, paginated by skip/limit.",
        "parameters": [
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "Number of records to skip (pagination offset)",
            "example": "0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Maximum number of records to return",
            "example": "50",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of cash transactions"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/transactions/current": {
      "get": {
        "operationId": "CashRegistersController_fetchCurrentTransactions",
        "summary": "List cash transactions for the current open shift of a register",
        "description": "Returns the cash movements recorded since the register was opened (the in-progress snapshot), most recent first, together with the open time, who opened it and the running expected balance. Returns an empty list when the register is closed.",
        "parameters": [
          {
            "name": "registerId",
            "required": true,
            "in": "query",
            "description": "Id of the cash register whose current (open) shift transactions should be returned",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "Number of records to skip (pagination offset)",
            "example": 0,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Maximum number of records to return",
            "example": 200,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current shift transactions and summary"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/transactions/by-range": {
      "get": {
        "operationId": "CashRegistersController_fetchTransactionsByRange",
        "summary": "List cash transactions for a device and date range",
        "description": "Returns cash movements recorded by a specific device over an ISO date range.",
        "parameters": [
          {
            "name": "deviceId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of cash transactions in the range"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/snapshots": {
      "get": {
        "operationId": "CashRegistersController_fetchSnapshots",
        "summary": "List cash register snapshots",
        "description": "Returns the closing snapshots (shifts) recorded for the caller locations over a date range, paginated.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {}
          },
          {
            "name": "limit",
            "required": true,
            "in": "query",
            "example": 50,
            "schema": {}
          },
          {
            "name": "skip",
            "required": true,
            "in": "query",
            "example": 0,
            "schema": {}
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {}
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of snapshots"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/snapshots/paged": {
      "get": {
        "operationId": "CashRegistersController_fetchSnapshotsPage",
        "summary": "List a page of cash register snapshots with the matching total",
        "description": "Same filter and ordering as the list endpoint, paired with the total matching that filter so a caller can page rather than guess at a cap.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {}
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "example": 20,
            "schema": {}
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "example": 0,
            "schema": {}
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {}
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "A page of snapshots and the total matching the filter",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "records": [],
                    "total": 0
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/snapshots/fetchById": {
      "get": {
        "operationId": "CashRegistersController_fetchSnapshotById",
        "summary": "Fetch a snapshot by id",
        "description": "Returns a single cash register snapshot with the full breakdown of openings, sales, refunds, etc.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot details"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/snapshots/export": {
      "get": {
        "operationId": "CashRegistersController_exportSnapshotCsv",
        "summary": "Export a snapshot as CSV",
        "description": "Streams a CSV export of the specified snapshot (contents: cash movements + summary).",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file download"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/snapshots/{id}": {
      "put": {
        "operationId": "CashRegistersController_updateSnapshot",
        "summary": "Update a snapshot",
        "description": "Replaces the fields of an existing snapshot (amounts, descriptions, nested breakdowns).",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.UpdateCashSnapshot"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated snapshot"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-registers/snapshots/{id}/fix": {
      "post": {
        "operationId": "CashRegistersController_createSnapshotFix",
        "summary": "Record a correction for a snapshot",
        "description": "Registers an out-of-band fix to a snapshot (e.g. note explaining a difference) and optionally notifies staff.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateSnapshotFix"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fix applied to the snapshot"
          }
        },
        "tags": [
          "Cash"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/health": {
      "get": {
        "operationId": "HealthController_check",
        "summary": "Service health check",
        "description": "Returns the health status of the payments service and its dependencies. Used by uptime probes and orchestrators.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Health details per subsystem",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "mongodb": {
                      "status": "up"
                    },
                    "redis": {
                      "status": "up"
                    },
                    "payments-service": {
                      "status": "up"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Health"
        ]
      }
    },
    "/payments/subscribers": {
      "post": {
        "operationId": "SubscribersController_create",
        "summary": "Create a subscriber",
        "description": "Attaches the calling customer to a subscription program/template by completing a provider (Stripe/Ayden) checkout session.",
        "parameters": [
          {
            "name": "authorization",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.SubscriberPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created subscriber record plus provider references",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "status": "ACTIVE",
                    "programId": "64f1b8a2c3d4e5f6a7b8c9d1",
                    "externalSubscriptionId": "sub_1NVf4HKj8i9s3xYz"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Subscribers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/subscribers/customer": {
      "get": {
        "operationId": "SubscribersController_fetchByCustomer",
        "summary": "List subscriptions of the current customer",
        "description": "Returns the subscriptions attached to the calling customer session, optionally scoped by subscription id.",
        "parameters": [
          {
            "name": "sid",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of subscriber records for the customer"
          }
        },
        "tags": [
          "Subscribers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/subscriptions": {
      "post": {
        "operationId": "SubscriptionController_create",
        "summary": "Create a subscription product",
        "description": "Registers a new subscription offering (with price tiers and provider) for the caller company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.SubscriptionPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created subscription product",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "name": "Platomico Premium",
                    "provider": "STRIPE"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Subscriptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "SubscriptionController_fetch",
        "summary": "List subscription products for an endpoint",
        "description": "Returns the subscription products available at the caller endpoint (ordering site, QR, etc.).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of subscription products"
          }
        },
        "tags": [
          "Subscriptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/subscriptions/fetchById": {
      "get": {
        "operationId": "SubscriptionController_fetchById",
        "summary": "Fetch a subscription product by id",
        "description": "Returns a single subscription product scoped to the caller company.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription product"
          }
        },
        "tags": [
          "Subscriptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/subscriptions/stripe/session": {
      "post": {
        "operationId": "SubscriptionController_createSubscriptionSession",
        "summary": "Create a Stripe checkout session for a subscription",
        "description": "Starts a Stripe-hosted checkout session so the customer can buy a subscription.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.SubscriptionSession"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stripe checkout session URL and id",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "cs_test_a1b2c3d4",
                    "url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Subscriptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/subscriptions/stripe/portal": {
      "post": {
        "operationId": "SubscriptionController_createCustomerPortal",
        "summary": "Create a Stripe customer portal session",
        "description": "Returns a URL to the Stripe-hosted customer portal where the customer can manage their subscription.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CustomerPortal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer portal URL",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "url": "https://billing.stripe.com/p/session/live_a1b2c3d4"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Subscriptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/in-person/intent": {
      "post": {
        "operationId": "PaymentsController_createInPersonPaymentIntent",
        "summary": "Create an in-person payment intent (v2)",
        "description": "Creates a Stripe in-person payment intent for the given amount/currency. The device then presents the reader to complete the payment.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Charge"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment intent identifier",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "pi_1NVf4HKj8i9s3xYz",
                    "status": "requires_payment_method"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/in-person/with-card": {
      "post": {
        "operationId": "PaymentsController_processInPersonPaymentWithCard",
        "summary": "Process an in-person card payment (v2)",
        "description": "Creates a transaction and charges the reader paired to the calling member session. Runs the full v2 payment pipeline.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction result"
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "PaymentsController_cancelInPersonPaymentWithCard",
        "summary": "Cancel an in-flight in-person payment (v2)",
        "description": "Cancels the in-person card payment currently attached to the caller device.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Cancellation result"
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/in-person/with-cash": {
      "post": {
        "operationId": "PaymentsController_processInPersonPaymentWithCash",
        "summary": "Process an in-person cash payment (v2)",
        "description": "Records an in-person cash payment via the v2 pipeline, computes change based on tendered amount, and persists the transaction.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction result with change calculation"
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/in-person/with-card-manual": {
      "post": {
        "operationId": "PaymentsController_processInPersonPaymentWithCardManual",
        "summary": "Process an in-person manual card payment (v2)",
        "description": "Records a card payment that was charged outside the paired terminal (manually by staff). Runs the v2 pipeline without opening the cash drawer or tracking a cash register movement. Only available from POS; any other source gets a 400.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction result"
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/in-person/custom": {
      "post": {
        "operationId": "PaymentsController_processCustomAmount",
        "summary": "Charge a custom amount (v2)",
        "description": "Takes an operator-typed amount with no catalog product behind it — a deposit, a correction, a one-off service — and runs it through the full v2 in-person pipeline for the chosen method. Produces a transaction, a KDS card and a printed ticket carrying a single line labelled \"Custom amount\" unless a label is given. Currency is the location currency, never the caller. CARD_MANUAL is POS-only.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CustomCharge"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "transactionId": "68a3f1c2d4e5f6a7b8c9d0e1"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/online/token": {
      "post": {
        "operationId": "PaymentsController_createOnlinePaymentToken",
        "summary": "Create an online payment token (v2)",
        "description": "Tokenises an order so the online payment can be confirmed in a later step (e.g. once the customer chooses their method).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token reference",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "token": "tok_1NVf4HKj8i9s3xYz"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/online/intent": {
      "post": {
        "operationId": "PaymentsController_createOnlinePaymentIntent",
        "summary": "Create an online payment intent (v2)",
        "description": "Creates a Stripe/Revolut payment intent for an online order that the frontend will then confirm.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment intent client secret and metadata",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "clientSecret": "pi_1NVf4HKj8i9s3xYz_secret_abc",
                    "id": "pi_1NVf4HKj8i9s3xYz"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/online/with-card": {
      "post": {
        "operationId": "PaymentsController_processOnlinePaymentWithCard",
        "summary": "Process an online card payment (v2)",
        "description": "Charges a card for an online order in one shot (no separate intent step). Used by server-side flows.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction result"
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/apple-pay/register-domain": {
      "post": {
        "operationId": "PaymentsController_registerDomainForApplePay",
        "summary": "Register a domain for Apple Pay",
        "description": "Registers a web domain with Revolut so Apple Pay works on it. Domain must serve the Apple Pay verification file.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "shop.platomico.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registered domain record"
          }
        },
        "tags": [
          "Payments:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics": {
      "get": {
        "operationId": "StatisticsController_fetchStatistics",
        "summary": "Fetch transaction statistics",
        "description": "Returns aggregate transaction statistics (counts, amounts) for the caller device and filter window.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregate statistics",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "count": 42,
                    "totalAmount": 152500,
                    "currency": "EUR"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/device": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsFromDevice",
        "summary": "Fetch transaction statistics for the calling device",
        "description": "Returns aggregate transaction statistics scoped to the calling device session (e.g. per-POS dashboard).",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregate statistics for the device"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/service-type": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsByServiceType",
        "summary": "Fetch transaction statistics broken down by service type",
        "description": "Returns aggregate transaction statistics grouped by service type (DINE_IN, TAKE_AWAY, DELIVERY).",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics grouped by service type",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "serviceType": "DINE_IN",
                      "count": 18,
                      "totalAmount": 72000
                    },
                    {
                      "serviceType": "TAKE_AWAY",
                      "count": 14,
                      "totalAmount": 52000
                    },
                    {
                      "serviceType": "DELIVERY",
                      "count": 10,
                      "totalAmount": 28500
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/source": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsBySource",
        "summary": "Fetch transaction statistics broken down by source",
        "description": "Returns aggregate transaction statistics grouped by source/channel (POS, KIOSK, ORDERING, etc.).",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics grouped by source"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/finance-close": {
      "get": {
        "operationId": "StatisticsController_fetchFinanceCloseReport",
        "summary": "Fetch the financial close report",
        "description": "Returns the structured financial close report bundled by channel group, provider, category and VAT rate. Drives the analytics finance-close PDF/XLSX export.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Financial close report"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/source/bundle": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsBySourceBundle",
        "summary": "Fetch transaction statistics by source bundle",
        "description": "Returns transaction statistics grouped by an aggregated source bundle (e.g. \"delivery providers\" combines Glovo+UberEats).",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics grouped by source bundle"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/source/bundle/v2": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsBySourceBundleV2",
        "summary": "Fetch transaction statistics by source bundle (v2)",
        "description": "V2 endpoint. Uses a single unified builder so Products + Services = Gross sales (ex-IVA), aligned with the financial report PDF.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics grouped by source bundle (v2)"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/source/service-type": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsBySourceServiceType",
        "summary": "Fetch transaction statistics broken down by source and service type",
        "description": "Returns aggregate transaction statistics grouped by source and resolved service type (DINE_IN, TAKE_AWAY, DELIVERY), used for per-channel average ticket breakdowns.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics grouped by source and service type",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "source": "ORDERING",
                      "serviceType": "DELIVERY",
                      "orders": 40,
                      "incomes": 92000,
                      "refunds": 2000,
                      "netSales": 90000,
                      "averageTicket": 2250,
                      "currency": "EUR"
                    },
                    {
                      "source": "ORDERING",
                      "serviceType": "TAKE_AWAY",
                      "orders": 10,
                      "incomes": 15000,
                      "refunds": 0,
                      "netSales": 15000,
                      "averageTicket": 1500,
                      "currency": "EUR"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/items": {
      "get": {
        "operationId": "StatisticsController_fetchStatisticsByItems",
        "summary": "Fetch top-selling items",
        "description": "Returns aggregate sales statistics grouped by item id, sorted descending by revenue.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statistics grouped by item",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "itemId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Margherita Pizza",
                      "count": 31,
                      "totalAmount": 38750
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/items-sold": {
      "get": {
        "operationId": "StatisticsController_fetchItemsSold",
        "summary": "Fetch units sold per item and combo",
        "description": "Returns units sold per item and per combo over the range, grouped by name and tagged with kind ITEM | MEAL. Combos are counted once (their component items in steps are not unwound, so they are not double-counted).",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counts per item/combo",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "name": "Classic Burger",
                      "quantity": 58,
                      "kind": "ITEM"
                    },
                    {
                      "name": "Burger Combo",
                      "quantity": 12,
                      "kind": "MEAL"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/items-sold/by-source": {
      "get": {
        "operationId": "StatisticsController_fetchItemsSoldBySource",
        "summary": "Fetch units sold per item, combo and modifier, grouped by source",
        "description": "Returns a dictionary keyed by trace.source (KIOSK., WEB., POS., Glovo, UberEats, …). Each source holds entries keyed by catalog id, tagged with kind ITEM | MEAL | MODIFIER and `fromStep`. Top-level items/combos are fromStep:false (quantity = item.quantity); combo step components are fromStep:true ITEMs (quantity = meal.quantity × step.quantity); modifiers are MODIFIER entries counted on both top-level items (fromStep:false) and combo-step items (fromStep:true). Each entry also carries the sale-time `name` from the transaction snapshot. The caller shows top-level items+meals in the All view, the deep ITEM set in the Items view, all MODIFIER entries in the Modifiers view, and resolves ids → names from the catalog, falling back to `name` for third-party items absent from the catalog.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counts per item/combo id, keyed by source",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "KIOSK.": [
                      {
                        "id": "66ba13ae8072f791755129be",
                        "name": "Burger Combo",
                        "quantity": 8,
                        "kind": "MEAL",
                        "fromStep": false
                      },
                      {
                        "id": "662628a355bf9e4031e51f32",
                        "name": "Classic Burger",
                        "quantity": 40,
                        "kind": "ITEM",
                        "fromStep": true
                      },
                      {
                        "id": "66c0f1a29a7b1e0044d3aa10",
                        "name": "Extra cheese",
                        "quantity": 15,
                        "kind": "MODIFIER",
                        "fromStep": false
                      }
                    ],
                    "Glovo": [
                      {
                        "id": "SQ-EXT-8823",
                        "name": "Döner artesanal",
                        "quantity": 4,
                        "kind": "ITEM",
                        "fromStep": false
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/sales": {
      "get": {
        "operationId": "StatisticsController_fetchSalesStatistics",
        "summary": "Fetch sales statistics",
        "description": "Returns aggregate sales statistics (net/gross, discounts, taxes, fees) for the filter window.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sales totals",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "net": 140000,
                    "gross": 152500,
                    "discounts": 8000,
                    "taxes": 14250,
                    "fees": 3500
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/sales/by-location": {
      "get": {
        "operationId": "StatisticsController_fetchSalesStatisticsByLocation",
        "summary": "Fetch sales statistics grouped by location and day",
        "description": "Returns aggregate sales statistics (orders, incomes, refunds, discounts, taxes, fees) grouped by location and calendar day (bucketed in the given timezone). Used by the analytics sales report per-location matrix.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sales totals per location per day",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "date": "2026-07-13",
                      "unix": 1783987200,
                      "orders": 42,
                      "incomes": 152500,
                      "refunds": 2000,
                      "discounts": 8000,
                      "taxes": 14250,
                      "fees": 3500
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/statistics/dashboard": {
      "get": {
        "operationId": "StatisticsController_fetchDashboardStatistics",
        "summary": "Fetch the dashboard statistics bundle",
        "description": "Returns the consolidated statistics bundle used by the Platomico admin dashboard (sales, counts, rankings).",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard statistics bundle"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatistics",
        "summary": "Fetch transaction statistics (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/sales": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchSalesStatistics",
        "summary": "Fetch sales statistics (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/sales/by-location": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchSalesStatisticsByLocation",
        "summary": "Fetch sales statistics by location and day (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/service-type": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatisticsByServiceType",
        "summary": "Fetch statistics by service type (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/source": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatisticsBySource",
        "summary": "Fetch statistics by source (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/source/bundle": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatisticsBySourceBundle",
        "summary": "Fetch statistics by source bundle (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/source/bundle/v2": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatisticsBySourceBundleV2",
        "summary": "Fetch statistics by source bundle v2 (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/finance-close": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchFinanceCloseReport",
        "summary": "Fetch finance close report (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/items": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatisticsByItems",
        "summary": "Fetch top-selling items (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/items-sold/by-source": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchItemsSoldBySource",
        "summary": "Fetch units sold per item/combo by source (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3/statistics/source/service-type": {
      "get": {
        "operationId": "StatisticsTimeWindowsController_fetchStatisticsBySourceServiceType",
        "summary": "Fetch statistics by source and service type (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v3": {
      "get": {
        "operationId": "TransactionsListTimeWindowsController_fetchTransactions",
        "summary": "List transactions (time-of-day aware)",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Transactions:V3"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2": {
      "get": {
        "operationId": "TransactionsController_fetchTransactions",
        "summary": "List transactions (v2)",
        "description": "Returns a page of transactions for the caller company filtered by locations, date range, service type, source and payment method. Returns the rows only; use /paged when the total is needed.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The matching transactions",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "amount": 1250,
                      "currency": "EUR",
                      "createdAt": "2026-04-23T12:00:00.000Z",
                      "serviceType": "DINE_IN",
                      "source": "POS."
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/paged": {
      "get": {
        "operationId": "TransactionsController_fetchTransactionsPaged",
        "summary": "List transactions with their total (v2)",
        "description": "Same filter, ordering and scoping as the list endpoint, and additionally returns the total number of matching transactions so a caller can page without fetching everything. Order defaults to createdAt DESC; `sortBy` accepts an allowlisted field only.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of transactions and the total matching the filter",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "transactions": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "amount": 1250,
                        "currency": "EUR",
                        "createdAt": "2026-04-23T12:00:00.000Z",
                        "serviceType": "DINE_IN",
                        "source": "POS."
                      }
                    ],
                    "total": 4213
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/export": {
      "get": {
        "operationId": "TransactionsController_exportTransactionsCSV",
        "summary": "Export transactions as CSV",
        "description": "Streams a CSV export of the transactions matching the provided filter. One row per transaction.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file download"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/endpoint": {
      "get": {
        "operationId": "TransactionsController_fetchFromEndpoint",
        "summary": "Fetch a transaction from an endpoint",
        "description": "Returns a transaction for a customer-facing endpoint (QR, ordering). Used to render the post-payment screen.",
        "parameters": [
          {
            "name": "tid",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction details for the endpoint"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/by-id": {
      "get": {
        "operationId": "TransactionsController_fetchById",
        "summary": "Fetch a transaction by id",
        "description": "Returns a single Transactions:V2 document by its _id, scoped to the caller session company (and sub-companies for dashboard sessions). Used by dashboards and POS devices that need to render a specific transaction.",
        "parameters": [
          {
            "name": "transactionId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction details"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/invoice-link": {
      "get": {
        "operationId": "TransactionsController_fetchInvoiceLink",
        "summary": "Fetch an invoice link for a transaction",
        "description": "Returns a download/share link for the PDF invoice of the given transaction.",
        "parameters": [
          {
            "name": "tid",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice link",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "url": "https://cdn.platomico.com/invoices/64f1b8a2c3d4e5f6a7b8c9d0.pdf"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/endpoint/review": {
      "post": {
        "operationId": "TransactionsController_createReviewFromEndpoint",
        "summary": "Submit a review from an endpoint",
        "description": "Attaches a rating/comment left by the customer to a transaction (used by post-payment review screens).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateReview"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created review record"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/dashboard/statistics": {
      "get": {
        "operationId": "TransactionsController_fetchDashboardStatistics",
        "summary": "Fetch dashboard statistics bundle",
        "description": "Returns the consolidated dashboard statistics for the caller company over the filter window.",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Start of date range (inclusive)",
            "example": "2026-04-01T00:00:00.000Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "End of date range (exclusive)",
            "example": "2026-04-30T23:59:59.999Z",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to bucket the results",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search term (matches receipt/customer/etc.)",
            "example": "jane",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceType",
            "required": false,
            "in": "query",
            "description": "Filter by service type",
            "example": "DINE_IN",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Filter by origin source/channel",
            "example": "POS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentType",
            "required": false,
            "in": "query",
            "description": "Filter by payment method",
            "example": "CARD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentTypes",
            "required": false,
            "in": "query",
            "description": "Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter.",
            "example": [
              "CARD",
              "CASH"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "granularity",
            "required": false,
            "in": "query",
            "description": "Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate.",
            "example": "day",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded.",
            "example": "IN_PROGRESS",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "description": "Field to order by. Defaults to createdAt so an unsorted request keeps its existing order.",
            "example": "amount",
            "schema": {
              "enum": [
                "createdAt",
                "amount",
                "status",
                "trace.source",
                "order.pickup.type"
              ],
              "type": "string"
            }
          },
          {
            "name": "sortDirection",
            "required": false,
            "in": "query",
            "description": "Order direction. Defaults to DESC.",
            "example": "ASC",
            "schema": {
              "enum": [
                "ASC",
                "DESC"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard statistics bundle"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/refund": {
      "post": {
        "operationId": "TransactionsController_refund",
        "summary": "Refund a transaction",
        "description": "Issues a refund (full or partial) against a payment of the caller company. Records the member or email of the requester.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.RefundPayloadV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Refund result"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/print": {
      "post": {
        "operationId": "TransactionsController_printReceipt",
        "summary": "Print a transaction receipt",
        "description": "Sends a print job to a receiver/printer for the given transaction. Supports different templates.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.PrintReceiptDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Print job acknowledgement"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/print/push": {
      "post": {
        "operationId": "TransactionsController_pushPrint",
        "summary": "Push a transaction receipt to a specific device",
        "description": "Queues one or more print templates for the given transaction onto the specified target printer. Authenticated as a device.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.PushPrintDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Print job acknowledgement with the list of queued templates",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "PRINT_QUEUED",
                    "queued": [
                      "PRINT_RECEIPT"
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/order-sequence": {
      "get": {
        "operationId": "TransactionsController_fetchOrderSequence",
        "summary": "Peek the next daily order sequence number for this device",
        "description": "Returns the number this location's next sale will get, wrapped to its last 2 digits (e.g. the 388th order returns 88). READ-ONLY: it does not consume the number — the server assigns the real one when the sale is created, and returns the same figure. Used by the POS to show the operator an order number when the customer name step is skipped or disabled — a display label, not a fiscal number.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The next sequence number (0-99), not yet consumed",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "sequence": 88
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/transactions/v2/receipt-image": {
      "get": {
        "operationId": "TransactionsController_receiptImage",
        "summary": "Render a transaction receipt as PNG",
        "description": "Renders the receipt for the given transaction as a PNG image (used for chat/email previews).",
        "parameters": [
          {
            "name": "tid",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "template",
            "required": false,
            "in": "query",
            "example": "default",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PNG image of the receipt"
          }
        },
        "tags": [
          "Transactions:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/open-tables": {
      "post": {
        "operationId": "OpenTablesController_open",
        "summary": "Open a table (DINE_IN, POS)",
        "description": "Creates an IN_PROGRESS transaction with no payments and pushes the kitchen order to the KDS. Pass tableId to seat the bill at a managed table (claims it); omit it for a walk-in bill. The table is charged later through the charge endpoint or a split session.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Id of the open-table transaction",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "transactionId": "6a3011516192e184593e950d"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:OpenTables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/open-tables/{transactionId}/items": {
      "post": {
        "operationId": "OpenTablesController_syncItems",
        "summary": "Update an open table (sync items)",
        "description": "Receives the FULL current cart and syncs the bill and the kitchen ticket to it: new lines arrive unchecked on the KDS, removed lines drop off the ticket, quantity changes update in place (checked flags preserved).",
        "parameters": [
          {
            "name": "transactionId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sync result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "transactionId": "6a3011516192e184593e950d",
                    "appendedItemsCount": 2,
                    "removedItemsCount": 1,
                    "changedItemsCount": 0
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:OpenTables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/open-tables/{transactionId}/charge": {
      "post": {
        "operationId": "OpenTablesController_charge",
        "summary": "Charge an open table",
        "description": "Completes the IN_PROGRESS transaction with the payment method in body.payment.method (CASH, CARD or CARD_MANUAL). Unsynced cart edits are pushed to the KDS first. Split charges go through the split-session endpoints with bill.transactionId instead.",
        "parameters": [
          {
            "name": "transactionId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Id of the completed transaction",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "transactionId": "6a3011516192e184593e950d"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:OpenTables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/open-tables/{transactionId}/join": {
      "post": {
        "operationId": "OpenTablesController_join",
        "summary": "Join another open bill into this one (juntar mesas)",
        "description": "Merges the source open bill into the target: items and totals combine on the target, the source transaction becomes CANCELED with a mergedInto marker, and its table is freed. The source kitchen ticket stays on the KDS (two tickets, one bill).",
        "parameters": [
          {
            "name": "transactionId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Join result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "transactionId": "6a3011516192e184593e950d",
                    "joinedFrom": "6a3011516192e184593e950e"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:OpenTables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/open-tables/{transactionId}/void": {
      "post": {
        "operationId": "OpenTablesController_voidOpenTable",
        "summary": "Void an open table",
        "description": "Cancels an IN_PROGRESS open-table transaction and its KDS order. PIN/permission gating happens on the POS client.",
        "parameters": [
          {
            "name": "transactionId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Void result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "voided": true,
                    "transactionId": "6a3011516192e184593e950d"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Payments:OpenTables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/flows": {
      "get": {
        "operationId": "FlowsController_fetch",
        "summary": "List configured payment flows",
        "description": "Returns the payment flows (ordered step sequences) configured for the caller company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of flow records",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Default checkout flow",
                      "useCase": "CARD",
                      "steps": [
                        {
                          "action": "PROCESS_PAYMENT",
                          "settings": {}
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Payments:Flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "FlowsController_create",
        "summary": "Create a payment flow",
        "description": "Creates a new payment flow (a named list of steps executed in order to complete a checkout).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateFlow"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created flow record"
          }
        },
        "tags": [
          "Payments:Flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "FlowsController_update",
        "summary": "Update the current payment flow",
        "description": "Updates the flow associated with the caller session. Payload shape is derived from the session scope.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Updated flow record"
          }
        },
        "tags": [
          "Payments:Flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "FlowsController_delete",
        "summary": "Delete the current payment flow",
        "description": "Removes the flow associated with the caller session.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Payments:Flows"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/tables": {
      "get": {
        "operationId": "TablesController_fetch",
        "summary": "List the location tables",
        "description": "Returns the active tables for the caller location. Occupancy is exposed as trace.transactionId (the seated open-table transaction) — null means free. Stale claims are self-healed on read.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Tables with occupancy state"
          }
        },
        "tags": [
          "Tables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "TablesController_create",
        "summary": "Create a table",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateTable"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created table"
          }
        },
        "tags": [
          "Tables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/tables/{tableId}": {
      "patch": {
        "operationId": "TablesController_update",
        "summary": "Update a table",
        "description": "Rename, change zone/seats, or archive (active: false). Archiving is rejected with 409 while the table is occupied.",
        "parameters": [
          {
            "name": "tableId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.UpdateTable"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update result"
          }
        },
        "tags": [
          "Tables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/inventory": {
      "post": {
        "operationId": "CashMachinesController_reportInventory",
        "summary": "Report what the cash machine is holding",
        "description": "Sent with the heartbeat. The cloud cannot read the machine itself — it is on the venue LAN — so this cache is the only way an operator sees the cash without walking to it. Overwrites the previous reading; never affects a sale.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.ReportCashInventoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "recorded": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/pending": {
      "get": {
        "operationId": "CashMachinesController_fetchPendingJobs",
        "summary": "List cash jobs waiting for this device",
        "description": "Polled by the till as a fallback for a dropped SSE connection. Returns only PENDING jobs addressed to the calling device.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Pending cash jobs",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "operation": "CHARGE",
                      "cashMachineId": "64f1b8a2c3d4e5f6a7b8c9e0",
                      "sequenceNumber": "m5k2p9qx4a1",
                      "amount": 1234,
                      "currency": "EUR"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/cancel-active": {
      "post": {
        "operationId": "CashMachinesController_cancelActiveJob",
        "summary": "Abort the cash operation this device currently has running",
        "description": "Operator-initiated cancel, the cash equivalent of cancelling a card checkout. The job id is resolved from the calling device because the job was created inside the still-in-flight charge request. Returns SUCCESS when the machine completed before the cancel landed — the customer has paid and the caller must treat it as a completed sale.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "CANCELED"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/{jobId}/claim": {
      "post": {
        "operationId": "CashMachinesController_claimJob",
        "summary": "Claim a cash job before driving the machine",
        "description": "Moves the job from PENDING to RUNNING. Returns claimed:false when another poller got there first — the caller must then not touch the machine.",
        "parameters": [
          {
            "name": "jobId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "claimed": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/{jobId}/state": {
      "get": {
        "operationId": "CashMachinesController_readJobState",
        "summary": "Is this job still mine to run?",
        "description": "Polled by the till WHILE it drives the machine. The cancel command travels over SSE, and the situations that most need it — app closed, backgrounded, off Wi-Fi — are the ones that lose it; a charge that never hears the cancel keeps the acceptor open and blocks the machine for the next sale. `live` false means stop touching the machine. Scoped to the calling device, and a job that is not this device's reads as not live.",
        "parameters": [
          {
            "name": "jobId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "live": true,
                    "status": "RUNNING"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/{jobId}/progress": {
      "post": {
        "operationId": "CashMachinesController_reportProgress",
        "summary": "Report how much cash the customer has inserted so far",
        "description": "Progress only — it never settles anything and the recorded tender always comes from the machine total on the result. Its purpose is the operator screen: without it a customer feeding coins for two minutes looks identical to a stalled machine. Safe to call repeatedly; each call overwrites the previous figure.",
        "parameters": [
          {
            "name": "jobId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CashChargeProgress"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "recorded": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-jobs/{jobId}/result": {
      "post": {
        "operationId": "CashMachinesController_postJobResult",
        "summary": "Report what the cash machine did",
        "description": "Settles the job the payment flow is waiting on. Totals must come from the machine, not from operator input — they become the recorded tender and change. A result for an already-settled job is stored and flagged as a late result rather than discarded.",
        "parameters": [
          {
            "name": "jobId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.PostCashJobResult"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "settled": true,
                    "status": "SUCCESS"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/charges": {
      "post": {
        "operationId": "CashChargesController_createCharge",
        "summary": "Start a cash-machine charge (does not wait)",
        "description": "Creates a durable cash charge, hands it to the linked till and returns immediately. The customer may take minutes; poll GET /:cashChargeId for progress and the final outcome. The sale is recorded server-side once the machine confirms the cash, so the outcome survives a lost connection, a closed app or a service restart.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateCashChargeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashChargeView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Charges"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/charges/{cashChargeId}": {
      "get": {
        "operationId": "CashChargesController_readCharge",
        "summary": "Poll a cash charge",
        "description": "Returns status, how much the customer has inserted so far, and the outcome once settled. Cheap and idempotent — safe to call every second.",
        "parameters": [
          {
            "name": "cashChargeId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashChargeView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Charges"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/charges/{cashChargeId}/cancel": {
      "post": {
        "operationId": "CashChargesController_cancelCharge",
        "summary": "Cancel a cash charge",
        "description": "Aborts a charge the customer has not completed; the machine returns any cash inserted. Refused once the machine has taken the money — at that point the sale is being recorded and cancelling would strand the cash. Returns the resulting state, so a cancel that lost the race reports the real outcome.",
        "parameters": [
          {
            "name": "cashChargeId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashChargeView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Charges"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/deposits": {
      "post": {
        "operationId": "CashDepositsController_createDeposit",
        "summary": "Start a cash-machine deposit (does not wait)",
        "description": "Creates a durable cash deposit, hands it to the linked till and returns immediately. The operator feeds cash toward the declared amount; poll GET /:cashDepositId for progress and the final outcome — the machine dispenses any excess back as change and settles on its own, same as a charge. The register ledger is updated server-side once the machine confirms the cash, so the outcome survives a lost connection, a closed app or a service restart.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateCashDepositRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashDepositView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Deposits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/deposits/{cashDepositId}": {
      "get": {
        "operationId": "CashDepositsController_readDeposit",
        "summary": "Poll a cash deposit",
        "description": "Returns status, how much has been inserted so far, and the outcome once settled. Cheap and idempotent — safe to call every second.",
        "parameters": [
          {
            "name": "cashDepositId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashDepositView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Deposits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/deposits/{cashDepositId}/cancel": {
      "post": {
        "operationId": "CashDepositsController_cancelDeposit",
        "summary": "Cancel a cash deposit",
        "description": "Aborts a deposit the operator has not finished; the machine returns any cash inserted. Refused once the machine has taken the money — at that point the ledger movement is being recorded and cancelling would strand the cash.",
        "parameters": [
          {
            "name": "cashDepositId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashDepositView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Deposits"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/withdrawals": {
      "post": {
        "operationId": "CashWithdrawalsController_createWithdrawal",
        "summary": "Start a cash-machine withdrawal (does not wait)",
        "description": "Creates a durable cash withdrawal, hands it to the linked till and returns immediately. Poll GET /:cashWithdrawalId for the outcome once the machine finishes dispensing. The register ledger is updated server-side once the machine confirms the dispense, so the outcome survives a lost connection, a closed app or a service restart.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateCashWithdrawalRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashWithdrawalView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Withdrawals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/withdrawals/{cashWithdrawalId}": {
      "get": {
        "operationId": "CashWithdrawalsController_readWithdrawal",
        "summary": "Poll a cash withdrawal",
        "description": "Returns status and the outcome once settled. Cheap and idempotent — safe to call every second.",
        "parameters": [
          {
            "name": "cashWithdrawalId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashWithdrawalView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Withdrawals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/withdrawals/{cashWithdrawalId}/cancel": {
      "post": {
        "operationId": "CashWithdrawalsController_cancelWithdrawal",
        "summary": "Cancel a cash withdrawal",
        "description": "Aborts a withdrawal before the machine has dispensed. Refused once the machine has paid the cash out — at that point the ledger movement is being recorded.",
        "parameters": [
          {
            "name": "cashWithdrawalId",
            "required": true,
            "in": "path",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CashWithdrawalView"
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Withdrawals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/cash-machines/inventory": {
      "get": {
        "operationId": "CashInventoriesController_fetchInventory",
        "summary": "Cash held by the machines at a location",
        "description": "Returns what each machine is holding — split into notes and coins, because coins are what limit change and refunds — plus any cash currently being collected or paid out. The two are separate: money a customer is inserting right now is in neither figure yet.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "description": "Defaults to the session's location",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/payments.CashMachineInventoryView"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Cash:Machines"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/loyalty/enabled": {
      "get": {
        "operationId": "LoyaltyController_enabled",
        "summary": "Whether loyalty is enabled for a location",
        "description": "Returns { enabled: true, provider } when loyalty is available for the location. Lets the POS decide whether to surface the loyalty identification step and which provider-specific affordances (such as QR scanning) apply. Device sessions resolve their own location; callers whose session is not bound to one (endpoint/customer sessions, e.g. the customer portal reading a receipt) must pass locationId.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Loyalty enablement"
          }
        },
        "tags": [
          "Payments:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/loyalty/accrual": {
      "get": {
        "operationId": "LoyaltyController_accrual",
        "summary": "Points a transaction has already earned",
        "description": "Returns { accrued, points? } for a transaction the caller can see. Lets a receipt page show \"you already collected these points\" without attempting a claim the outbox would reject. Scoped to the session company and returns no customer data.",
        "parameters": [
          {
            "name": "transactionId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Accrual state for the transaction"
          }
        },
        "tags": [
          "Payments:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/loyalty/claim": {
      "post": {
        "operationId": "LoyaltyController_claim",
        "summary": "Claim the loyalty points for a transaction",
        "description": "Credits the points for a completed transaction to the signed-in customer, enrolling them in the company's loyalty program when the provider supports it. Accrual only — this never redeems a reward. Identity comes from the customer session, never the request body, and the transaction must belong to the session company. Claiming twice is a no-op: a transaction already linked to a customer (including one identified at the till) reports ALREADY_CLAIMED.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.ClaimLoyaltyPointsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Claim outcome",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.ClaimLoyaltyPointsResponse"
                }
              }
            }
          }
        },
        "tags": [
          "Payments:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/loyalty/resolve": {
      "post": {
        "operationId": "LoyaltyController_resolve",
        "summary": "Resolve a loyalty customer and their applicable promotions",
        "description": "Looks up the customer in the active loyalty provider for the location and returns their promotions as selectable discounts. Returns { found: false } when the company has no active loyalty contract.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.ResolveLoyaltyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Loyalty resolution"
          }
        },
        "tags": [
          "Payments:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/split/session": {
      "post": {
        "operationId": "SplitSessionsController_create",
        "summary": "Create a split-payment session",
        "description": "Creates a new split-payment session from a bill and a plan. Returns the session with a JWT-signed token used to resume on crash.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.CreateSplitSession"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created session"
          }
        },
        "tags": [
          "Split Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "SplitSessionsController_resume",
        "summary": "Resume a split-payment session by token",
        "description": "Verifies the JWT token and returns the latest session state from the database.",
        "parameters": [
          {
            "name": "token",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resumed session"
          }
        },
        "tags": [
          "Split Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/split/leg": {
      "post": {
        "operationId": "SplitSessionsController_appendLeg",
        "summary": "Append a leg (AMOUNT-mode only)",
        "description": "Appends a new PENDING leg to an AMOUNT-mode session. Rejects if the new sum would exceed the bill total.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.AppendLeg"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated session and the new leg"
          }
        },
        "tags": [
          "Split Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/split/leg/{identifier}/charge": {
      "post": {
        "operationId": "SplitSessionsController_chargeLeg",
        "summary": "Charge a single leg",
        "description": "Charges the specified leg through the per-method flow (CASH opens the drawer, CARD hits the terminal, CARD_MANUAL records as success). Sets leg COMPLETED or FAILED.",
        "parameters": [
          {
            "name": "identifier",
            "required": true,
            "in": "path",
            "example": "01HXYZ...",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.ChargeLeg"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated session and the charged leg"
          }
        },
        "tags": [
          "Split Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/split/session/abort": {
      "post": {
        "operationId": "SplitSessionsController_abort",
        "summary": "Abort a split session",
        "description": "Marks the session FAILED. Refunds COMPLETED CARD legs through their gateway. CASH/CARD_MANUAL legs are marked REFUNDED for manual reversal.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.AbortSession"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Aborted session with refunded legs"
          }
        },
        "tags": [
          "Split Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/v2/split/session/finalize": {
      "post": {
        "operationId": "SplitSessionsController_finalize",
        "summary": "Finalize a fully-paid split session",
        "description": "Runs the post-payment pipeline (verify legs, build bill, push to KDS, track consumption, create transaction) and returns the resulting transaction id.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/payments.FinalizeSession"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Finalized session and the transaction id"
          }
        },
        "tags": [
          "Split Payments"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/platform/success": {
      "get": {
        "operationId": "PlatformController_success",
        "summary": "Complete provider onboarding (redirect target)",
        "description": "Landing URL Stripe/Revolut redirects to after a successful onboarding flow. Finalises the account and redirects the user back to the app.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Stripe connected account id",
            "example": "acct_1NVf4HKj8i9s3xYz",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Redirect response to the onboarding success page"
          }
        },
        "tags": [
          "Platform"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/platform/refresh": {
      "get": {
        "operationId": "PlatformController_refresh",
        "summary": "Refresh the provider onboarding link (redirect target)",
        "description": "Landing URL Stripe/Revolut redirects to when an onboarding link expires. Issues a new onboarding link and redirects there.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Stripe connected account id",
            "example": "acct_1NVf4HKj8i9s3xYz",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Redirect response to a fresh onboarding link"
          }
        },
        "tags": [
          "Platform"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/platform/connection-token": {
      "get": {
        "operationId": "PlatformController_fetchConnectionToken",
        "summary": "Fetch a Stripe Terminal connection token",
        "description": "Returns a short-lived connection token used by the Stripe Terminal SDK to pair with a card reader.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Connection token",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "secret": "pst_test_a1b2c3d4e5f6"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Platform"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/payments/payouts": {
      "get": {
        "operationId": "PayoutsController_collect",
        "summary": "Collect payouts across gateways (JIT)",
        "description": "Searches every payout-capable gateway configured for the company (Stripe, Square, Revolut) for the given date range, upserts the results into the store (completed payouts are never overwritten), and returns the stored view newest-first. Fail-open: a gateway with missing credentials or an API error is reported under `sources` and the stored rows are still returned.",
        "parameters": [
          {
            "name": "providers",
            "required": false,
            "in": "query",
            "description": "Comma-separated gateways to collect from. Defaults to all payout-capable gateways.",
            "example": "STRIPE,SQUARE",
            "schema": {
              "enum": [
                "DEFAULT",
                "ADYEN",
                "SQUARE",
                "STRIPE",
                "REVOLUT",
                "GLOVO",
                "CASH",
                "CARD"
              ],
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "Lower bound on payout creation time (ISO 8601)",
            "example": "2026-06-01T00:00:00.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "Upper bound on payout creation time (ISO 8601)",
            "example": "2026-06-30T23:59:59.000Z",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "currency",
            "required": false,
            "in": "query",
            "description": "Filter by ISO 4217 currency code",
            "example": "EUR",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Maximum payouts to collect per gateway (1-100)",
            "example": 50,
            "schema": {
              "default": 50,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/payments.CollectPayoutsResult"
                }
              }
            }
          }
        },
        "tags": [
          "Transactions:Payouts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/health": {
      "get": {
        "operationId": "HealthController_check",
        "summary": "Service health check",
        "description": "Returns the health status of the supply-chain service and its dependencies. Used by uptime probes and orchestrators.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Health details per subsystem",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "mongodb": {
                      "status": "up"
                    },
                    "redis": {
                      "status": "up"
                    },
                    "supply-chain-service": {
                      "status": "up"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Health"
        ]
      }
    },
    "/supply-chain/items": {
      "post": {
        "operationId": "ItemsController_create",
        "summary": "Create an item (legacy)",
        "description": "Creates a menu item (dish / drink) for the current company. Legacy pipeline with floating-point rounding issues — prefer POST /v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Item"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Item"
                }
              }
            }
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "ItemsController_fetch",
        "summary": "List items",
        "description": "Returns items available at the given location ids for the current company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of items",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/supply-chain.Item"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ItemsController_update",
        "summary": "Update an item (legacy)",
        "description": "Updates an existing item. Legacy pipeline with floating-point rounding issues — prefer PATCH /v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Partial Item payload with required id",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  },
                  "name": {
                    "type": "string",
                    "example": "Classic Burger"
                  },
                  "price": {
                    "type": "object",
                    "example": {
                      "amount": 1250,
                      "currency": "EUR"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated item"
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ItemsController_delete",
        "summary": "Delete an item",
        "description": "Deletes the item with the given id from the current company.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Identifier of the item",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/v2": {
      "post": {
        "operationId": "ItemsController_createV2",
        "summary": "Create an item",
        "description": "Creates a menu item (dish / drink) for the current company using the v2 pipeline (normalized pricing).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Item"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Item"
                }
              }
            }
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ItemsController_updateV2",
        "summary": "Update an item",
        "description": "Updates an existing item using the v2 pipeline (normalized pricing, image upload).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Partial Item payload with required id",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  },
                  "name": {
                    "type": "string",
                    "example": "Classic Burger"
                  },
                  "price": {
                    "type": "object",
                    "example": {
                      "amount": 1250,
                      "currency": "EUR"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated item"
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/paged": {
      "get": {
        "operationId": "ItemsController_fetchPage",
        "summary": "List a page of items",
        "description": "Same scope as the list endpoint, narrowed to one page and paired with the total matching the same filter, so a caller can page without fetching the whole catalogue. Omitting `limit` returns everything, exactly as the list endpoint does.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search over the record name.",
            "example": "burger",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of items and the total matching the filter",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "records": [],
                    "total": 0
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/endpoint": {
      "get": {
        "operationId": "ItemsController_fetchFromEndpoint",
        "summary": "List items for an endpoint (ordering site)",
        "description": "Returns items available to a public endpoint (ordering web, QR) scoped to the endpoint session and locations. Filters by visibility channel.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Items visible on the endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/supply-chain.Item"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/consumables": {
      "post": {
        "operationId": "ConsumablesController_create",
        "summary": "Create a consumable (legacy)",
        "description": "Creates a new consumable (raw ingredient, drink base, etc.) for the current company. Legacy endpoint that does not apply the v2 pricing fixes — prefer POST /v2 for new code.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Consumable"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created consumable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Consumable"
                }
              }
            }
          }
        },
        "tags": [
          "Consumables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ConsumablesController_update",
        "summary": "Update a consumable (legacy)",
        "description": "Updates an existing consumable. Legacy endpoint; prefer PATCH /v2 which normalizes price to cents.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Partial consumable with the id of the target document",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  },
                  "name": {
                    "type": "string",
                    "example": "Tomato"
                  },
                  "price": {
                    "type": "object",
                    "example": {
                      "amount": 250,
                      "currency": "EUR",
                      "measure": "grs"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated consumable"
          }
        },
        "tags": [
          "Consumables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "ConsumablesController_fetchMany",
        "summary": "List consumables for a location",
        "description": "Returns consumables available at the given location for the current company.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Identifier of the location to scope the query to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of consumables",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/supply-chain.Consumable"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Consumables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ConsumablesController_delete",
        "summary": "Delete a consumable",
        "description": "Deletes the consumable with the given id. Fails if it is still referenced by items / preparations / stock.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Identifier of the consumable",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Consumables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/consumables/v2": {
      "post": {
        "operationId": "ConsumablesController_createV2",
        "summary": "Create a consumable",
        "description": "Creates a new consumable (raw ingredient, drink base, etc.) for the current company using the v2 pipeline (normalized pricing + image upload).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Consumable"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created consumable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Consumable"
                }
              }
            }
          }
        },
        "tags": [
          "Consumables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ConsumablesController_updateV2",
        "summary": "Update a consumable",
        "description": "Updates an existing consumable using the v2 pipeline (normalized pricing + image upload).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Partial consumable with the id of the target document",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  },
                  "name": {
                    "type": "string",
                    "example": "Tomato"
                  },
                  "price": {
                    "type": "object",
                    "example": {
                      "amount": 250,
                      "currency": "EUR",
                      "measure": "grs"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated consumable"
          }
        },
        "tags": [
          "Consumables"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/locales": {
      "get": {
        "operationId": "LocalesController_fetch",
        "summary": "List locales for a menu",
        "description": "Returns all translation documents attached to the given menu. Used by the admin UI to display translation coverage.",
        "parameters": [
          {
            "name": "menuId",
            "required": true,
            "in": "query",
            "description": "Menu id to scope the query to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of locale documents",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "type": "ITEM",
                      "trace": {
                        "sourceId": "64f1b8a2c3d4e5f6a7b8c9d4",
                        "lang": "en"
                      },
                      "locales": {
                        "en": "Classic Burger",
                        "es": "Hamburguesa Clásica"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Locales"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "LocalesController_create",
        "summary": "Create a locale",
        "description": "Creates a new translation document for an entity (item, meal, menu, section). Once persisted, downstream services use it to render localized strings.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateLocale"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created locale document"
          }
        },
        "tags": [
          "Locales"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "LocalesController_update",
        "summary": "Update a locale",
        "description": "Updates the translations or display name of an existing locale document.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateLocale"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated locale document"
          }
        },
        "tags": [
          "Locales"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/locales/base-dictionaries": {
      "get": {
        "operationId": "LocalesController_baseDictionaries",
        "summary": "Platform base dictionaries for device/web UI strings",
        "description": "Returns the canonical ES base UI strings for the DEVICE (POS/kiosk/KDS) and ENDPOINT (web storefront) scopes. These are platform-global (identical for every company), so the admin Languages tab can translate devices/web for a brand-new company that has no per-company locale documents yet.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Base dictionaries keyed by scope type",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "DEVICE": {
                      "bill.total.pos": "Total"
                    },
                    "ENDPOINT": {
                      "order.total": "Total"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Locales"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/locales/by-type": {
      "get": {
        "operationId": "LocalesController_fetchLocalesByType",
        "summary": "List locales by type",
        "description": "Returns all locale documents of a given type (ITEM, MEAL, MENU, SECTION, ...) for the current company.",
        "parameters": [
          {
            "name": "type",
            "required": true,
            "in": "query",
            "example": "ITEM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Locale documents of the given type",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "type": "ITEM",
                      "locales": {
                        "en": "Classic Burger",
                        "es": "Hamburguesa Clásica"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Locales"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/locales/bulk": {
      "post": {
        "operationId": "LocalesController_bulkUpsert",
        "summary": "Bulk create/update locales",
        "description": "Creates or updates many locale documents in one call. Each item is matched by company + source + type + lang (or by localeId) and its translations are merged into any existing document. Emits a single REFRESH_LOCALES event. Used by the admin Locales settings tab to persist an auto-translated language across a menu.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.BulkUpsertLocales"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Counts of created and updated locale documents",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "created": 1,
                    "updated": 2
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Locales"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/menus": {
      "get": {
        "operationId": "MenusController_fetch",
        "summary": "List menus",
        "description": "Returns menus defined at the given location ids for the current company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of menus",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Lunch Menu",
                      "type": "DEFAULT",
                      "sections": [
                        {
                          "name": "Starters",
                          "items": []
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Menus"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "MenusController_create",
        "summary": "Create a menu",
        "description": "Creates a new menu (DEFAULT = per-item pricing, DAILY = flat price) with its sections / items for the current company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateMenu"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created menu"
          }
        },
        "tags": [
          "Menus"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "MenusController_update",
        "summary": "Update a menu",
        "description": "Updates an existing menu: sections, items, theme, availability windows, discounts.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateMenu"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated menu"
          }
        },
        "tags": [
          "Menus"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "MenusController_delete",
        "summary": "Delete a menu",
        "description": "Permanently removes the menu with the given id from the current company.",
        "parameters": [
          {
            "name": "menuId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Menus"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/menus/{menuId}/publish": {
      "post": {
        "operationId": "MenusController_publish",
        "summary": "Publish a menu",
        "description": "Promotes the menu's unpublished edits onto its live keys — the moment they become visible to devices and platforms. Pass `channels` to publish a subset; omit it to publish everything pending. Publishing nothing is a no-op, not an error.",
        "parameters": [
          {
            "name": "menuId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "example": {
                  "channels": [
                    "CUSTOMER",
                    "EMPLOYEE"
                  ]
                },
                "properties": {
                  "channels": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "CUSTOMER",
                        "EMPLOYEE",
                        "DELIVERY",
                        "MENU_LEVEL"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The published menu and the channels that were promoted",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "published": [
                      "CUSTOMER"
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Menus"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/menus/{menuId}/discard": {
      "post": {
        "operationId": "MenusController_discard",
        "summary": "Discard a menu draft",
        "description": "Throws away unpublished edits without touching live content. Pass `channels` to discard a subset; omit it to discard everything pending.",
        "parameters": [
          {
            "name": "menuId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "example": {
                  "channels": [
                    "DELIVERY"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The menu and the channels that were discarded",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "discarded": [
                      "DELIVERY"
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Menus"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/modifiers": {
      "post": {
        "operationId": "ModifiersController_create",
        "summary": "Create a modifier (legacy)",
        "description": "Creates an item modifier (topping, extra, size) for the current company. Legacy endpoint that does not convert price to cents — prefer POST /v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Modifier"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created modifier",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Modifier"
                }
              }
            }
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "ModifiersController_fetch",
        "summary": "List modifiers",
        "description": "Returns modifiers available at the given location ids for the current company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of modifiers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/supply-chain.Modifier"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ModifiersController_update",
        "summary": "Update a modifier (legacy)",
        "description": "Updates an existing modifier. Legacy endpoint that does not convert price to cents — prefer PATCH /v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateModifier"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated modifier"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ModifiersController_delete",
        "summary": "Delete a modifier",
        "description": "Deletes the modifier with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Identifier of the modifier",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/modifiers/v2": {
      "post": {
        "operationId": "ModifiersController_createV2",
        "summary": "Create a modifier",
        "description": "Creates an item modifier (topping, extra, size) for the current company using the v2 pipeline (normalized pricing).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Modifier"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created modifier",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Modifier"
                }
              }
            }
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ModifiersController_updateV2",
        "summary": "Update a modifier",
        "description": "Updates an existing modifier using the v2 pipeline (normalized pricing).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateModifier"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated modifier"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/modifiers/endpoint": {
      "get": {
        "operationId": "ModifiersController_fetchFromEndpoint",
        "summary": "List modifiers for an endpoint",
        "description": "Returns modifiers available to a public endpoint (ordering web, QR) scoped to the endpoint session and locations.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Modifiers visible on the endpoint"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/items/modifiers/groups": {
      "get": {
        "operationId": "ModifierGroupsController_fetch",
        "summary": "List modifier groups",
        "description": "Returns modifier groups available at the given locations for the current company. Used by the modifier editor combobox.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of modifier groups",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/supply-chain.ModifierGroup"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Modifier Groups"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ModifierGroupsController_update",
        "summary": "Update a modifier group",
        "description": "Updates a modifier group. Setting `limits` turns the group into a bounded selection section (min/max counted in units); passing `limits: null` returns it to a plain label. Rejects bounds the group cannot satisfy and members already bound by another section.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateModifierGroup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated modifier group"
          },
          "400": {
            "description": "Unreachable or contradictory bounds, or a member already bound elsewhere"
          }
        },
        "tags": [
          "Modifier Groups"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/inventory/stores": {
      "get": {
        "operationId": "InventoryController_getStockStore",
        "summary": "List stock stores",
        "description": "Returns the stock stores (current inventory) for the given location ids within the current company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stock stores grouped by location",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d4",
                      "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Tomato",
                      "amount": 5000,
                      "measure": "grs",
                      "trace": {
                        "locationId": "64f1b8a2c3d4e5f6a7b8c9d1"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Inventory"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/inventory/store": {
      "post": {
        "operationId": "InventoryController_createStockStore",
        "summary": "Create a stock store",
        "description": "Creates a stock store entry (initial inventory) for a consumable at a specific location.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateStockStore"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created stock store",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d4",
                    "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "amount": 5000,
                    "measure": "grs",
                    "trace": {
                      "locationId": "64f1b8a2c3d4e5f6a7b8c9d1"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Inventory"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "InventoryController_updateStockStore",
        "summary": "Update stock stores at a location",
        "description": "Bulk updates the stock levels for the given consumables at a specific location. Used by the \"count inventory\" flow.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateStockStore"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Summary of the update",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "updated": 3
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Inventory"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "InventoryController_deleteStockStore",
        "summary": "Delete a stock store",
        "description": "Removes a stock store entry (by id) for the given location.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d4",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d4"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Inventory"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/inventory/track/consumption-v2": {
      "post": {
        "operationId": "InventoryController_trackConsumptionV2",
        "summary": "Track consumption from a transaction (v2)",
        "description": "Given a transaction id (optionally an order id), walks the items/modifiers/preparations, decrements stock stores, and emits consumption events. Called by POS/integrations after a sale is completed.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "transactionId"
                ],
                "properties": {
                  "transactionId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d5"
                  },
                  "orderId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d6"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Summary of the consumption tracking",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "consumedCount": 12,
                    "transactionId": "64f1b8a2c3d4e5f6a7b8c9d5"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Inventory"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/inventory/retrack/consumptions-v2": {
      "post": {
        "operationId": "InventoryController_retrackConsumptionsV2",
        "summary": "Re-track (regenerate) consumptions in a range",
        "description": "Regenerates Consumptions:V2 documents for the given locations and date range from their source transactions, applying the current consumption logic. Used to repair historical analytics. Does NOT decrement stock and preserves each doc original createdAt. Call with confirm:false first for a dry-run count.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "locationsIds",
                  "from",
                  "to"
                ],
                "properties": {
                  "locationsIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "example": [
                      "64f1b8a2c3d4e5f6a7b8c9d1"
                    ]
                  },
                  "from": {
                    "type": "string",
                    "example": "2026-04-01T00:00:00.000Z"
                  },
                  "to": {
                    "type": "string",
                    "example": "2026-04-23T23:59:59.999Z"
                  },
                  "confirm": {
                    "type": "boolean",
                    "example": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Summary of the re-track run (or dry-run count)",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "matched": 120,
                    "retracked": 118,
                    "skipped": 2,
                    "confirmed": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Inventory"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/preparations": {
      "post": {
        "operationId": "PreparationsController_create",
        "summary": "Create a preparation",
        "description": "Creates a preparation (mise en place / sub-recipe that aggregates ingredients into a reusable building block). Consumed by items and other preparations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.Preparation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created preparation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/supply-chain.Preparation"
                }
              }
            }
          }
        },
        "tags": [
          "Preparations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "PreparationsController_update",
        "summary": "Update a preparation",
        "description": "Updates an existing preparation (name, ingredients, serving unit, tags).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "description": "Partial preparation with its id",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  },
                  "name": {
                    "type": "string",
                    "example": "House Tomato Sauce"
                  },
                  "ingredients": {
                    "type": "array",
                    "example": [
                      {
                        "type": "INGREDIENT",
                        "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                        "amount": 1000,
                        "measure": "grs"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated preparation"
          }
        },
        "tags": [
          "Preparations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "PreparationsController_fetchMany",
        "summary": "List preparations at a location",
        "description": "Returns preparations defined at the given location for the current company.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Identifier of the location to scope the query to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of preparations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/supply-chain.Preparation"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Preparations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "PreparationsController_delete",
        "summary": "Delete a preparation",
        "description": "Deletes the preparation with the given id. Fails if still referenced by items or other preparations.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Identifier of the preparation",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Preparations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/dashboard": {
      "get": {
        "operationId": "AnalyticsController_getDashboardData",
        "summary": "Get analytics dashboard data",
        "description": "Returns the aggregated numbers (sales, top items, consumption summary) rendered on the dashboard home for the given time range and optional locations.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard metrics for the range",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "sales": {
                      "amount": 125000,
                      "currency": "EUR",
                      "count": 342
                    },
                    "topItems": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "name": "Classic Burger",
                        "count": 58
                      }
                    ],
                    "consumptionCost": {
                      "amount": 38500,
                      "currency": "EUR"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/stock-timestamps": {
      "get": {
        "operationId": "AnalyticsController_getStockTimestamps",
        "summary": "Get stock level timestamps",
        "description": "Returns stock snapshots across the requested range and locations (used to render stock-over-time charts).",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of stock snapshots keyed by consumable and timestamp",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Tomato",
                      "series": [
                        {
                          "timestamp": "2026-04-23T00:00:00.000Z",
                          "amount": 8000,
                          "measure": "grs"
                        },
                        {
                          "timestamp": "2026-04-23T12:00:00.000Z",
                          "amount": 6200,
                          "measure": "grs"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions": {
      "get": {
        "operationId": "AnalyticsController_getConsumptions",
        "summary": "Get consumptions in the range",
        "description": "Returns consumption data grouped by the given bucket size (minutes) or by calendar date.",
        "parameters": [
          {
            "name": "range",
            "required": true,
            "in": "query",
            "example": "15",
            "schema": {
              "enum": [
                "5",
                "10",
                "15",
                "30",
                "60",
                "date"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consumption totals grouped by bucket",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "bucket": "2026-04-23T12:00:00.000Z",
                      "consumable": "Tomato",
                      "amount": 300,
                      "measure": "grs"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/items/v2/consumption": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsV2",
        "summary": "Get item-level consumption (v2)",
        "description": "Returns the v2 item-level consumption breakdown (uses transactionsV2 as source). Supports bucket sizes in minutes or by calendar date.",
        "parameters": [
          {
            "name": "range",
            "required": true,
            "in": "query",
            "example": "60",
            "schema": {
              "enum": [
                "5",
                "10",
                "15",
                "30",
                "60",
                "date"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Item consumption breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "bucket": "2026-04-23T12:00:00.000Z",
                      "itemId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Classic Burger",
                      "count": 12
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/snapshot/items": {
      "get": {
        "operationId": "AnalyticsController_getSnapshotItemsAllTimeRecord",
        "summary": "Get all-time record snapshots for items",
        "description": "Returns snapshot records for the given item names and frequency. Used to plot historical sales curves.",
        "parameters": [
          {
            "name": "itemsNames",
            "required": true,
            "in": "query",
            "example": [
              "Classic Burger",
              "Margherita Pizza"
            ],
            "schema": {
              "type": "array",
              "items": {}
            }
          },
          {
            "name": "frequency",
            "required": true,
            "in": "query",
            "example": "daily",
            "schema": {
              "enum": [
                "daily",
                "hourly",
                "weekly",
                "monthly",
                "yearly"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot records per item",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "name": "Classic Burger",
                      "series": [
                        {
                          "timestamp": "2026-04-22T00:00:00.000Z",
                          "count": 58
                        },
                        {
                          "timestamp": "2026-04-23T00:00:00.000Z",
                          "count": 61
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/v2/time-series": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsV2PerIngredientTimeSeries",
        "summary": "Consumption time-series per ingredient (v2)",
        "description": "Returns a time-series of ingredient consumption over the given range. Used for trend charts.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Time-series per ingredient",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Tomato",
                      "series": [
                        {
                          "timestamp": "2026-04-23T00:00:00.000Z",
                          "amount": 1500,
                          "measure": "grs"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/v2/items": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsV2ItemsSold",
        "summary": "Items sold in the range (v2)",
        "description": "Returns the number of units sold per item for the given range. Aggregated from transactionsV2.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counts per item",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "itemId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Classic Burger",
                      "count": 58
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/v2/items-and-meals": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsV2ItemsAndMealsSold",
        "summary": "Items and meal deals sold in the range (v2)",
        "description": "Returns units sold per item and per meal deal for the given range. Each row is tagged with kind ITEM or MEAL. Meal deals are only recorded for consumptions created after this field was introduced.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counts per item and per meal deal",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "name": "Classic Burger",
                      "totalQuantitySold": 58,
                      "kind": "ITEM"
                    },
                    {
                      "name": "Burger Combo",
                      "totalQuantitySold": 12,
                      "kind": "MEAL"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/v2/preparations-time-series": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsV2PerPreparationTimeSeries",
        "summary": "Preparation consumption time-series (v2)",
        "description": "Returns a time-series of preparation (sub-recipe) consumption over the given range. Sourced from the consumption records `preparations` array.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Time-series per preparation",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "date": "2026-04-23",
                      "preparations": [
                        {
                          "preparationIdentifier": "64f1b8a2c3d4e5f6a7b8c9d0",
                          "name": "Pizza dough",
                          "totalAmount": 12400
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/v2/preparations": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsPreparationsCount",
        "summary": "Preparation consumption totals (v2)",
        "description": "Returns total consumption per preparation for the range, with each preparation rolled up to its resolved raw consumables.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Totals per preparation with resolved consumable breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "preparation": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Pizza dough",
                      "used": 12400,
                      "resolved": [
                        {
                          "consumable": "64f1b8a2c3d4e5f6a7b8c9d1",
                          "used": 8000
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/count": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsCounted",
        "summary": "Count consumptions in range",
        "description": "Returns the total number of consumption events recorded in the range.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Count of consumption events",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "count": 342
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/average": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsAverage",
        "summary": "Average consumption for the company",
        "description": "Returns the company's average consumption per bucket across its lifetime. No range parameters.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Average consumption metrics",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "averageDailyConsumptionCost": {
                      "amount": 38500,
                      "currency": "EUR"
                    },
                    "averageDailyOrders": 322
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/consumptions/variance": {
      "get": {
        "operationId": "AnalyticsController_getConsumptionsVariance",
        "summary": "Consumption variance in range",
        "description": "Returns the variance between expected (based on sales + recipes) and observed consumption, either as an absolute number or relative percentage.",
        "parameters": [
          {
            "name": "type",
            "required": true,
            "in": "query",
            "example": "RELATIVE",
            "schema": {
              "enum": [
                "RELATIVE",
                "ABSOLUTE"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Variance breakdown per consumable",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Tomato",
                      "variance": 0.12
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/items/sales": {
      "get": {
        "operationId": "AnalyticsController_fetchSales",
        "summary": "Fetch item sales in range",
        "description": "Returns per-item sales totals (count + revenue) for the given range and locations.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sales totals per item",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "itemId": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Classic Burger",
                      "count": 58,
                      "revenue": {
                        "amount": 72500,
                        "currency": "EUR"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/purchase-orders/count": {
      "get": {
        "operationId": "AnalyticsController_getOrdersCounted",
        "summary": "Count purchase orders in range",
        "description": "Returns the number of purchase orders placed in the range, grouped by status.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Purchase order counts by status",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "PENDING": 3,
                    "IN_PROGRESS": 2,
                    "RECEIVED": 12,
                    "COMPLETED": 10
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Analytics"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/v2/consumptions/v2/time-series": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_getConsumptionsV2PerIngredientTimeSeries",
        "summary": "Consumption time-series per ingredient (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Variance comparison mode (consumptions/variance only)",
            "example": "RELATIVE",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/v2/consumptions/v2/items": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_getConsumptionsV2ItemsSold",
        "summary": "Items sold from consumptions v2 (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Variance comparison mode (consumptions/variance only)",
            "example": "RELATIVE",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/v2/consumptions/v2/preparations-time-series": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_getConsumptionsV2PerPreparationTimeSeries",
        "summary": "Preparation consumption time-series (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Variance comparison mode (consumptions/variance only)",
            "example": "RELATIVE",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/v2/consumptions/v2/preparations": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_getConsumptionsPreparationsCount",
        "summary": "Preparation consumption totals (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Variance comparison mode (consumptions/variance only)",
            "example": "RELATIVE",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/v2/consumptions/count": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_getConsumptionsCounted",
        "summary": "Count consumptions in range (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Variance comparison mode (consumptions/variance only)",
            "example": "RELATIVE",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/analytics/v2/consumptions/variance": {
      "get": {
        "operationId": "AnalyticsTimeWindowsController_getConsumptionsVariance",
        "summary": "Consumptions variance (time-of-day aware)",
        "parameters": [
          {
            "name": "locationsIds",
            "required": false,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timeWindows",
            "required": false,
            "in": "query",
            "description": "Intra-day windows to keep, each \"startMinute-endMinute\" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day.",
            "example": [
              "720-960",
              "1140-1380"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "timezone",
            "required": false,
            "in": "query",
            "description": "IANA timezone used to evaluate the time windows",
            "example": "Europe/Madrid",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Variance comparison mode (consumptions/variance only)",
            "example": "RELATIVE",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Analytics:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/purchase-orders": {
      "get": {
        "operationId": "PurchaseOrdersController_fetch",
        "summary": "List purchase orders in range",
        "description": "Returns purchase orders placed at the given locations within the date range, optionally filtered by status.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of purchase orders",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "status": "PENDING",
                      "provider": "64f1b8a2c3d4e5f6a7b8c9d3",
                      "createdAt": "2026-04-20T09:30:00.000Z",
                      "items": [
                        {
                          "consumable": "64f1b8a2c3d4e5f6a7b8c9d7",
                          "amount": 5000,
                          "measure": "grs",
                          "price": {
                            "amount": 300,
                            "currency": "EUR"
                          }
                        }
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "PurchaseOrdersController_create",
        "summary": "Create purchase orders",
        "description": "Creates one or more purchase orders (one per provider) for the given location. Each order contains the consumables to order with their amounts and prices.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateOrder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created orders",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "status": "PENDING",
                      "provider": "64f1b8a2c3d4e5f6a7b8c9d3"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "PurchaseOrdersController_update",
        "summary": "Update a purchase order",
        "description": "Updates a purchase order status (e.g. mark as IN_PROGRESS, RECEIVED, CANCELED) and optionally attaches a delivery note.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateOrder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated order"
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "PurchaseOrdersController_delete",
        "summary": "Delete a purchase order",
        "description": "Deletes the purchase order with the given id from the listed locations.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Id of the purchase order to delete",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids the purchase order belongs to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/purchase-orders/paged": {
      "get": {
        "operationId": "PurchaseOrdersController_fetchPage",
        "summary": "List a page of purchase orders with the matching total",
        "description": "Same filter and ordering as the list endpoint, narrowed to one page and paired with the total matching that filter. The page is taken before the reception lookup, so the join runs only for the rows returned. Omitting `limit` returns everything, exactly as the list endpoint does.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "A page of purchase orders and the total matching the filter",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "records": [],
                    "total": 0
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/purchase-orders/provider": {
      "get": {
        "operationId": "PurchaseOrdersController_fetchByProvider",
        "summary": "List purchase orders for a provider",
        "description": "Returns paginated purchase orders filtered by provider within the range and locations.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Purchase orders from the provider",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "total": 12,
                    "items": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "status": "RECEIVED",
                        "createdAt": "2026-04-20T09:30:00.000Z"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/purchase-orders/one": {
      "get": {
        "operationId": "PurchaseOrdersController_fetchOne",
        "summary": "Fetch a single purchase order",
        "description": "Returns a purchase order by its id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The purchase order",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "status": "IN_PROGRESS",
                    "provider": "64f1b8a2c3d4e5f6a7b8c9d3",
                    "items": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/purchase-orders/device": {
      "get": {
        "operationId": "PurchaseOrdersController_fetchPendingOrders",
        "summary": "List pending purchase orders for a device",
        "description": "Returns the purchase orders pending reception at the member / device location. Used on-site when receiving a delivery.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Pending purchase orders",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "status": "PENDING",
                      "provider": "64f1b8a2c3d4e5f6a7b8c9d3"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/purchase-orders/kanban": {
      "get": {
        "operationId": "PurchaseOrdersController_fetchKanban",
        "summary": "Kanban board of purchase orders",
        "description": "Returns purchase orders grouped by status, suited for a kanban UI.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Purchase orders grouped by status",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "PENDING": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "provider": "64f1b8a2c3d4e5f6a7b8c9d3"
                      }
                    ],
                    "IN_PROGRESS": [],
                    "RECEIVED": [],
                    "COMPLETED": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/providers": {
      "post": {
        "operationId": "ProvidersController_create",
        "summary": "Create a provider",
        "description": "Creates a supplier / provider record for the current company (used by purchase orders and receptions).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateProvider"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created provider",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d3",
                    "name": "Mercamadrid",
                    "email": "orders@mercamadrid.com",
                    "phone": "+34910001234"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ProvidersController_update",
        "summary": "Update a provider",
        "description": "Updates the contact details or reference of an existing provider.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateProvider"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated provider"
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "ProvidersController_fetchMany",
        "summary": "List providers",
        "description": "Returns all providers configured for the current company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of providers",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d3",
                      "name": "Mercamadrid",
                      "reference": "MM-2026"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ProvidersController_deleteProvider",
        "summary": "Delete a provider",
        "description": "Deletes the provider with the given id. Does not delete its measures; those must be removed separately.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d3",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d3"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/providers/measure": {
      "get": {
        "operationId": "ProvidersController_fetchMeasures",
        "summary": "List provider measures (packaging) at locations",
        "description": "Returns the packaging units (measures) a provider sells for consumables at the given locations. Used during reception to map a quantity to a price.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of measures",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d9",
                      "name": "Caja 5kg tomate rama",
                      "amount": 5000,
                      "measure": "grs",
                      "price": {
                        "amount": 1800,
                        "currency": "EUR"
                      },
                      "trace": {
                        "providerId": "64f1b8a2c3d4e5f6a7b8c9d3",
                        "locationsIds": [
                          "64f1b8a2c3d4e5f6a7b8c9d1"
                        ],
                        "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "ProvidersController_createMeasure",
        "summary": "Create a provider measure (packaging)",
        "description": "Creates a packaging unit for a consumable sold by a provider at one or more locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateMeasure"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created measure"
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ProvidersController_updateMeasure",
        "summary": "Update a provider measure",
        "description": "Updates a provider measure (packaging size, price, linked consumables, reference).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateMeasure"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated measure"
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ProvidersController_deleteMeasure",
        "summary": "Delete a provider measure",
        "description": "Deletes the provider measure (packaging) with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d9",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d9"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/meals": {
      "post": {
        "operationId": "MealsController_create",
        "summary": "Create a meal (legacy)",
        "description": "Creates a meal (combo) for the current company. Legacy endpoint that does not normalize price to cents and skips image upload — prefer POST /v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateMeal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created meal"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "MealsController_update",
        "summary": "Update a meal (legacy)",
        "description": "Updates an existing meal. Legacy endpoint with floating-point pricing issues — prefer PATCH /v2.",
        "deprecated": true,
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateMeal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated meal"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "MealsController_delete",
        "summary": "Delete a meal",
        "description": "Deletes the meal with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Identifier of the meal",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "MealsController_fetch",
        "summary": "List meals",
        "description": "Returns meals available at the given location ids for the current company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of meals",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Burger Combo",
                      "price": {
                        "amount": 1800,
                        "currency": "EUR"
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/meals/v2": {
      "post": {
        "operationId": "MealsController_createV2",
        "summary": "Create a meal",
        "description": "Creates a meal (combo: a sequence of steps letting the customer pick items) for the current company. v2 pipeline normalizes price and uploads images.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateMeal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created meal"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "MealsController_updateV2",
        "summary": "Update a meal",
        "description": "Updates an existing meal using the v2 pipeline (normalized pricing, image upload).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateMeal"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated meal"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/meals/paged": {
      "get": {
        "operationId": "MealsController_fetchPage",
        "summary": "List a page of meals",
        "description": "Same scope as the list endpoint, narrowed to one page and paired with the total matching the same filter, so a caller can page without fetching the whole catalogue. Omitting `limit` returns everything, exactly as the list endpoint does.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search over the record name.",
            "example": "burger",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of meals and the total matching the filter",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "records": [],
                    "total": 0
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/meals/endpoint": {
      "get": {
        "operationId": "MealsController_fetchFromEndpoint",
        "summary": "List meals for an endpoint",
        "description": "Returns meals available to a public endpoint (ordering web, QR) scoped to the endpoint session and locations.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the management list (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Meals visible on the endpoint"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/steps": {
      "post": {
        "operationId": "StepsController_create",
        "summary": "Create a master step",
        "description": "Creates a reusable meal-step template for the current company. Meals copy its contents when the step is added and stamp the copy with stepId for provenance.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateStep"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created master step"
          }
        },
        "tags": [
          "Steps"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "StepsController_update",
        "summary": "Update a master step",
        "description": "Updates an existing master step. Meals that already copied it are NOT rewritten.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateStep"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated master step"
          }
        },
        "tags": [
          "Steps"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "StepsController_delete",
        "summary": "Delete a master step",
        "description": "Deletes the master step with the given id. Meals keep their copied contents.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Identifier of the master step",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Steps"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "StepsController_fetch",
        "summary": "List master steps",
        "description": "Returns master steps available at the given location ids for the current company.",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "includeHidden",
            "required": false,
            "in": "query",
            "description": "When true, also return records hidden from the picker (visible:false). Defaults to false. Note: arrives as the string \"true\"/\"false\" (query params are not transformed).",
            "example": true,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of master steps",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Sauces",
                      "view": "MODIFIERS",
                      "limits": {
                        "min": 0,
                        "free": 0,
                        "max": 2
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Steps"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/steps/propagate": {
      "patch": {
        "operationId": "StepsController_propagate",
        "summary": "Propagate a master step into meals",
        "description": "Replaces the whole step body of every meal step copied from this master step (matched by stepId) with the master step's current contents. Company-scoped and opt-in.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateStep"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "How many meals matched and were modified",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "matchedMeals": 3,
                    "modifiedMeals": 3
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Steps"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/orphans": {
      "get": {
        "operationId": "ReceptionsController_getOrphansReceptions",
        "summary": "List orphan receptions",
        "description": "Returns receptions that exist but are not yet linked to a purchase order (typically deliveries that arrived unexpectedly).",
        "parameters": [
          {
            "name": "locationsIds",
            "required": true,
            "in": "query",
            "description": "Location ids to scope the query to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Orphan receptions",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "locationId": "64f1b8a2c3d4e5f6a7b8c9d1",
                      "createdAt": "2026-04-23T08:00:00.000Z",
                      "status": "PENDING"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/device/upload-delivery-note": {
      "post": {
        "operationId": "ReceptionsController_uploadDeliveryNoteFromDevice",
        "summary": "Upload delivery note from a device",
        "description": "Uploads delivery note images captured on a device (POS/tablet). Skips duplicate detection when force is true.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UploadDeliveryNodeFromDevice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload result with the created delivery note id",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "deliveryNoteId": "64f1b8a2c3d4e5f6a7b8c9d5",
                    "fileUrls": [
                      "https://cdn.platomico.com/delivery-notes/dn-abc.pdf"
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/upload-delivery-note": {
      "post": {
        "operationId": "ReceptionsController_uploadDeliveryNote",
        "summary": "Upload delivery note for a location",
        "description": "Uploads delivery note images for a specific location. Returns the created delivery note id and file URLs.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UploadDeliveryNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "deliveryNoteId": "64f1b8a2c3d4e5f6a7b8c9d5",
                    "fileUrls": [
                      "https://cdn.platomico.com/delivery-notes/dn-abc.pdf"
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/analyze": {
      "post": {
        "operationId": "ReceptionsController_analyze",
        "summary": "Analyze a delivery note (OCR + extraction)",
        "description": "Runs OCR + extraction on the uploaded delivery note images and returns the parsed line items (provider, consumables, prices).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.AnalyzeDeliveryNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Extracted delivery note data",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "deliveryNoteId": "64f1b8a2c3d4e5f6a7b8c9d5",
                    "provider": {
                      "name": "Mercamadrid"
                    },
                    "items": [
                      {
                        "name": "Tomate rama",
                        "quantity": 5,
                        "measure": "kg",
                        "price": {
                          "amount": 1800,
                          "currency": "EUR"
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/analyze-with-agent": {
      "post": {
        "operationId": "ReceptionsController_analyzeWithAgent",
        "summary": "Analyze a delivery note via the AI agent",
        "description": "Analyzes the delivery note using the AI agent pipeline (slower, more accurate). Returns the parsed line items.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.AnalyzeDeliveryNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Extracted delivery note data",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "deliveryNoteId": "64f1b8a2c3d4e5f6a7b8c9d5",
                    "provider": {
                      "name": "Mercamadrid"
                    },
                    "items": [
                      {
                        "name": "Tomate rama",
                        "quantity": 5,
                        "measure": "kg",
                        "price": {
                          "amount": 1800,
                          "currency": "EUR"
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/create": {
      "post": {
        "operationId": "ReceptionsController_create",
        "summary": "Create a reception (v2)",
        "description": "Persists a reception from the analyzed delivery note: matches consumables, creates/updates measures, and updates stock stores.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateReceptionV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created reception",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "deliveryNoteId": "64f1b8a2c3d4e5f6a7b8c9d5",
                    "status": "RECEIVED"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/staff/analyze": {
      "post": {
        "operationId": "ReceptionsController_analyzeDeliveryNote",
        "summary": "Analyze a delivery note (staff)",
        "description": "Runs the OCR / extraction pipeline on a delivery note, invoked via the staff console.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.AnalyzeDeliveryNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Extracted delivery note data"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/staff/create": {
      "post": {
        "operationId": "ReceptionsController_createReceptionV2",
        "summary": "Create a reception (staff)",
        "description": "Creates a reception using the v2 pipeline from the staff console (on behalf of the company attached to the session).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateReceptionV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created reception"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/staff/confirm": {
      "patch": {
        "operationId": "ReceptionsController_confirmReceptionFromStaff",
        "summary": "Confirm a reception (staff)",
        "description": "Marks the reception as confirmed from the staff console, recording final amounts and prices.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.StaffConfirmReception"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The confirmed reception"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/confirm": {
      "patch": {
        "operationId": "ReceptionsController_confirmReception",
        "summary": "Confirm a reception",
        "description": "Member confirms a reception once the goods are checked, locking final amounts and prices and updating stock stores.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.ConfirmReception"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The confirmed reception"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions": {
      "patch": {
        "operationId": "ReceptionsController_update",
        "summary": "Update a reception",
        "description": "Updates the consumables / packaging details on an existing reception before confirmation.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateReception"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated reception"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ReceptionsController_delete",
        "summary": "Delete a reception",
        "description": "Deletes the reception with the given id at the given location.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "description": "Id of the reception to delete",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Location the reception belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/fix": {
      "patch": {
        "operationId": "ReceptionsController_fix",
        "summary": "Fix a mismatched reception",
        "description": "Resolves a mismatch between ordered and received quantities by recording the corrected values. Produces audit records for accounting.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.FixReception"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The fixed reception"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/device": {
      "patch": {
        "operationId": "ReceptionsController_uploadReceptionFromDevice",
        "summary": "Update a reception from a device",
        "description": "Device-side endpoint to update a reception in progress (e.g. during the on-site goods-in flow).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateReception"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated reception"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/receptions/file": {
      "get": {
        "operationId": "ReceptionsController_proxyFile",
        "summary": "Proxy download a delivery note file",
        "description": "Server-side proxy that downloads a file (typically the delivery note PDF/image) from the given URL and streams it back with a Content-Disposition attachment header. Used to bypass CORS.",
        "parameters": [
          {
            "name": "url",
            "required": true,
            "in": "query",
            "example": "https://cdn.platomico.com/delivery-notes/dn-abc.pdf",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Binary file stream of the proxied resource"
          },
          "400": {
            "description": "Failed to download the requested file"
          }
        },
        "tags": [
          "Receptions"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/delivery/fees": {
      "post": {
        "operationId": "DeliveryController_createFeeRange",
        "summary": "Create a delivery fee range",
        "description": "Creates a fee tier (a minimum order threshold + percent fee) for the current company, optionally scoped to specific locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.CreateFeeRange"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created fee range",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "min": {
                      "amount": 2000,
                      "currency": "EUR"
                    },
                    "type": "PERCENT",
                    "amount": 10,
                    "currency": "EUR",
                    "trace": {
                      "companyId": "64f1b8a2c3d4e5f6a7b8c9d1",
                      "locationsIds": [
                        "64f1b8a2c3d4e5f6a7b8c9d2"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "get": {
        "operationId": "DeliveryController_fetchFeeRanges",
        "summary": "List delivery fee ranges",
        "description": "Returns the configured delivery fee tiers for the current company, optionally filtered by location.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of configured fee tiers",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "min": {
                        "amount": 2000,
                        "currency": "EUR"
                      },
                      "type": "PERCENT",
                      "amount": 10
                    },
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d3",
                      "min": {
                        "amount": 5000,
                        "currency": "EUR"
                      },
                      "type": "PERCENT",
                      "amount": 5
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "DeliveryController_updateFeeRange",
        "summary": "Update a delivery fee range",
        "description": "Updates the threshold, type or amount of an existing delivery fee tier.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateFeeRange"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated fee range"
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "DeliveryController_deleteFeeRange",
        "summary": "Delete a delivery fee range",
        "description": "Removes the delivery fee tier with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "deletedId": "64f1b8a2c3d4e5f6a7b8c9d0"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Delivery"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/allergens": {
      "get": {
        "operationId": "AllergensController_fetchMany",
        "summary": "List supported allergens",
        "description": "Returns the catalog of allergens Platomico supports (used to tag consumables, items and meals). Public endpoint.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of allergens",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "name": "Gluten",
                      "icon": "gluten.svg"
                    },
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d1",
                      "name": "Lactose",
                      "icon": "lactose.svg"
                    },
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                      "name": "Peanuts",
                      "icon": "peanuts.svg"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "Allergens"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/visibility": {
      "get": {
        "operationId": "VisibilityController_fetch",
        "summary": "Fetch catalog visibility",
        "description": "Returns the per-location, per-channel hidden state of items, meals and modifiers for the current company.",
        "parameters": [
          {
            "name": "locationIds",
            "required": false,
            "in": "query",
            "description": "Optional location ids to scope the read to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Visibility map keyed by location id then resource id. Channels whose snooze deadline has already passed are reported as visible.",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "64f1b8a2c3d4e5f6a7b8c9d1": {
                      "64f1b8a2c3d4e5f6a7b8c9d0": {
                        "type": "ITEM",
                        "hiddenChannels": [
                          "DELIVERY"
                        ],
                        "snoozeUntil": {
                          "DELIVERY": "2026-05-21T12:00:00.000Z"
                        },
                        "updatedAt": "2026-05-21T10:00:00.000Z"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Visibility"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "VisibilityController_update",
        "summary": "Toggle catalog visibility on a channel",
        "description": "Hides or shows an item, meal or modifier on a single channel across the given locations. Pass `until` to make the hide expire on its own.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateVisibility"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result of the toggle",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "resourceId": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "locationsUpdated": 2
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Visibility"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/visibility/bulk": {
      "patch": {
        "operationId": "VisibilityController_updateBulk",
        "summary": "Toggle catalog visibility for a whole group at once",
        "description": "Hides or shows every resource carrying the given tags (resolved server-side) plus any explicitly listed ones, on one channel across the given locations. Writes one record per member — there is no tag-level state, so products tagged afterwards are unaffected.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.UpdateVisibilityBulk"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result of the group toggle",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "resourcesUpdated": 14,
                    "locationsUpdated": 2
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Visibility"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/supply-chain/visibility/publish": {
      "post": {
        "operationId": "VisibilityController_publish",
        "summary": "Republish the platform catalog after availability changes",
        "description": "Queues a catalog sync for the given locations, which rebuilds BOTH feeds of every menu — the delivery menu and the store menus — with the current per-channel visibility applied. Returns as soon as the sync is queued: it can take minutes, and hidden products are already unavailable on the platforms by then through the per-product flip.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/supply-chain.PublishVisibilityMenus"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "How many locations were queued",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true,
                    "locationsQueued": 1
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Visibility"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/": {
      "get": {
        "operationId": "IntegrationsController_fetch",
        "summary": "List generic integration bindings",
        "description": "Returns every integration binding stored for the current company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Integration bindings for the company"
          }
        },
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "IntegrationsController_create",
        "summary": "Create a generic integration binding",
        "description": "Creates a binding between a Platomico entity and an external provider entity. If `both` is true, creates one binding in each direction.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.IntegrationPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created binding(s)"
          }
        },
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/items": {
      "get": {
        "operationId": "ItemsController_fetch",
        "summary": "List item bindings",
        "description": "Returns item bindings for the current company, filtered by the optional query. Array parameters accept a JSON-encoded string.",
        "parameters": [
          {
            "name": "defaultId",
            "required": true,
            "in": "query",
            "description": "The internal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "defaultType",
            "required": true,
            "in": "query",
            "description": "The type of the record",
            "schema": {
              "example": "ITEM",
              "type": "string"
            }
          },
          {
            "name": "externalIds",
            "required": true,
            "in": "query",
            "description": "The external id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "itemIds",
            "required": true,
            "in": "query",
            "description": "The internal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching item bindings"
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "ItemsController_create",
        "summary": "Create an item binding",
        "description": "Binds a Platomico item to an external provider item for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ItemPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created binding"
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ItemsController_update",
        "summary": "Update an item binding",
        "description": "Partially updates the item binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ItemPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated binding"
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ItemsController_delete",
        "summary": "Delete an item binding",
        "description": "Permanently removes the item binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Items"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/health": {
      "get": {
        "operationId": "HealthController_check",
        "summary": "Service health check",
        "description": "Returns liveness/readiness details for integrations-service. Used by load balancers and uptime monitors.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Health details for each dependency",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "mongodb": {
                      "status": "up"
                    },
                    "redis": {
                      "status": "up"
                    },
                    "integrations-service": {
                      "status": "up"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Health"
        ]
      }
    },
    "/integrations/parser/items": {
      "post": {
        "operationId": "ParserController_parseItems",
        "summary": "Parse items across providers",
        "description": "Given a binding direction and a provider, translates a list of items between Platomico and the external provider shape.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Array of items in either the Platomico or provider shape (depending on direction)",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed items in the opposite shape",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "SUCCESS",
                    "items": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/parser/modifiers": {
      "post": {
        "operationId": "ParserController_parseModifiers",
        "summary": "Parse modifiers across providers",
        "description": "Translates a list of modifiers between Platomico and the provider shape.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Array of modifiers in either the Platomico or provider shape",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed modifiers",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "SUCCESS",
                    "modifiers": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/parser/meals": {
      "post": {
        "operationId": "ParserController_parseMeals",
        "summary": "Parse meals across providers",
        "description": "Translates a list of meals between Platomico and the provider shape.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Array of meals in either the Platomico or provider shape",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed meals",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "SUCCESS",
                    "meals": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/parser/orders": {
      "post": {
        "operationId": "ParserController_parseOrdersPublic",
        "summary": "Parse an order across providers",
        "description": "Translates a single order between Platomico and the provider shape.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Order in either the Platomico or provider shape",
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed order",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "SUCCESS",
                    "orders": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/parser/locations": {
      "post": {
        "operationId": "ParserController_parseLocationsPublic",
        "summary": "Parse locations across providers",
        "description": "Translates a locations payload between Platomico and the provider shape.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ParserlocationPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed locations",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "SUCCESS",
                    "locations": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/parser/discounts": {
      "post": {
        "operationId": "ParserController_parseDiscountsPublic",
        "summary": "Parse discounts across providers",
        "description": "Translates a discounts payload between Platomico and the provider shape.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ParserDiscountsPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed discounts",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "status": "SUCCESS",
                    "discounts": []
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/parser/record": {
      "post": {
        "operationId": "ParserController_parseRecord",
        "summary": "Parse a single record by id",
        "description": "Fetches a record by id within a company and runs the parser on it. Handy for reprocessing a single failed record.",
        "parameters": [
          {
            "name": "binding",
            "required": true,
            "in": "query",
            "description": "The binding of the items",
            "schema": {
              "enum": [
                "LTR",
                "RTL"
              ],
              "type": "string"
            }
          },
          {
            "name": "provider",
            "required": true,
            "in": "query",
            "description": "The provider of the items",
            "schema": {
              "enum": [
                "DEFAULT",
                "SQUARE",
                "GLOVO"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "companyId"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d0"
                  },
                  "companyId": {
                    "type": "string",
                    "example": "64f1b8a2c3d4e5f6a7b8c9d1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed record"
          }
        },
        "tags": [
          "Parser"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/modifiers": {
      "get": {
        "operationId": "ModifiersController_fetch",
        "summary": "List modifier bindings",
        "description": "Returns modifier bindings for the current company, filtered by the optional query. Array parameters accept a JSON-encoded string.",
        "parameters": [
          {
            "name": "defaultId",
            "required": true,
            "in": "query",
            "description": "The internal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "defaultType",
            "required": true,
            "in": "query",
            "description": "The type of the record",
            "schema": {
              "example": "ITEM",
              "type": "string"
            }
          },
          {
            "name": "externalIds",
            "required": true,
            "in": "query",
            "description": "The external id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "modifierIds",
            "required": true,
            "in": "query",
            "description": "The id of the modifier",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching modifier bindings"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "ModifiersController_create",
        "summary": "Create a modifier binding",
        "description": "Binds a Platomico modifier to an external provider modifier for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ModifierPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created binding"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "ModifiersController_update",
        "summary": "Update a modifier binding",
        "description": "Partially updates the modifier binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ModifierPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated binding"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "ModifiersController_delete",
        "summary": "Delete a modifier binding",
        "description": "Permanently removes the modifier binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Modifiers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/meals/fetch": {
      "get": {
        "operationId": "MealsController_fetch",
        "summary": "List meal bindings",
        "description": "Returns meal bindings for the current company, filtered by the optional query. Array parameters accept a JSON-encoded string.",
        "parameters": [
          {
            "name": "defaultId",
            "required": true,
            "in": "query",
            "description": "The internal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "defaultType",
            "required": true,
            "in": "query",
            "description": "The type of the record",
            "schema": {
              "example": "ITEM",
              "type": "string"
            }
          },
          {
            "name": "externalIds",
            "required": true,
            "in": "query",
            "description": "The external id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "mealIds",
            "required": true,
            "in": "query",
            "description": "The meal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching meal bindings"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/meals": {
      "post": {
        "operationId": "MealsController_create",
        "summary": "Create a meal binding",
        "description": "Binds a Platomico meal to an external provider meal for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.MealPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created binding"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "MealsController_update",
        "summary": "Update a meal binding",
        "description": "Partially updates the meal binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.MealPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated binding"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "MealsController_delete",
        "summary": "Delete a meal binding",
        "description": "Permanently removes the meal binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Meals"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/discounts": {
      "get": {
        "operationId": "DiscountsController_fetch",
        "summary": "List discount bindings",
        "description": "Returns discount bindings for the current company, filtered by the optional query.",
        "parameters": [
          {
            "name": "defaultId",
            "required": true,
            "in": "query",
            "description": "The internal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "defaultType",
            "required": true,
            "in": "query",
            "description": "The type of the record",
            "schema": {
              "example": "ITEM",
              "type": "string"
            }
          },
          {
            "name": "externalIds",
            "required": true,
            "in": "query",
            "description": "The external id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "discountIds",
            "required": true,
            "in": "query",
            "description": "The internal id of the record",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching discount bindings"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "DiscountsController_create",
        "summary": "Create a discount binding",
        "description": "Binds a Platomico discount to an external provider discount for the given locations.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.DiscountPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created binding"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "DiscountsController_update",
        "summary": "Update a discount binding",
        "description": "Partially updates the discount binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.DiscountPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated binding"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "DiscountsController_delete",
        "summary": "Delete a discount binding",
        "description": "Permanently removes the discount binding with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Discounts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/square/parse": {
      "post": {
        "operationId": "SquareController_parseAsStaff",
        "summary": "Parse a Square item/meal",
        "description": "Runs the Square strategy parser, translating a single entity between Platomico and Square shapes in the given direction. Scoped by companyId on the payload.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ParseSquareStrategy"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed entity"
          }
        },
        "tags": [
          "Integrations:V2:Square"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/square/reconcile": {
      "post": {
        "operationId": "SquareController_reconcile",
        "summary": "Reconcile Square sales data with Platomico",
        "description": "Scans (or fixes) Square orders/payments for a date range to catch drift vs Platomico state. Session-scoped: the company is always resolved from the session token.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ReconcileSquareDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reconciliation report"
          }
        },
        "tags": [
          "Integrations:V2:Square"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/square/catalog/items/{itemId}/image": {
      "get": {
        "operationId": "SquareController_fetchCatalogItemImage",
        "summary": "Fetch the Square image for a bound catalog entity",
        "description": "Given a Platomico item/meal id, reports whether the company has a Square contract (connected), whether that entity has an ACTIVE Square binding (bound), and the current image URL of the bound Square catalog object. Item bindings are stored RTL (right = Square variation, left filled by matching), so the lookup scans the provider bindings by left.id. Falls back to the sync-time image snapshot on right.obj when the live Square lookup fails. Session-scoped: the company is resolved from the token.",
        "parameters": [
          {
            "name": "itemId",
            "required": true,
            "in": "path",
            "description": "Platomico item or meal id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability report",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "provider": "SQUARE",
                    "connected": true,
                    "bound": true,
                    "image": "https://items-images-production.s3.us-west-2.amazonaws.com/…"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Integrations:V2:Square"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/square/devices/code": {
      "post": {
        "operationId": "SquareController_createDeviceCode",
        "summary": "Create a Square Terminal pairing code",
        "description": "Creates a Square device code (Terminal API) for the location, resolved through its ACTIVE Square location binding. Entering the code on a Square POS/Terminal pairs it in Terminal mode. Returns 409 when the location has no active Square location binding.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.CreateSquareDeviceCode"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created Square device code (raw Square shape)"
          }
        },
        "tags": [
          "Integrations:V2:Square"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/square/devices/code/{id}": {
      "get": {
        "operationId": "SquareController_fetchDeviceCode",
        "summary": "Fetch a Square Terminal pairing code",
        "description": "Reads the device code back from Square to poll its pairing status. Once status is PAIRED, deviceId identifies the terminal for TerminalCheckouts. Tenant-safe: the lookup runs under the company session token.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Square device code id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Square device code (raw Square shape)"
          }
        },
        "tags": [
          "Integrations:V2:Square"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/revolut/devices": {
      "get": {
        "operationId": "RevolutController_fetchDevices",
        "summary": "List the Revolut POS terminals of a location",
        "description": "Reads the terminals Revolut already knows about for the location, resolved through its ACTIVE Revolut location binding. `id` is the value a Platomico TERMINAL device must store as trace.serial (payment intents address terminals by it); serialNumber is the number printed on the hardware and is display only. Returns 409 when the location has no active Revolut location binding.",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "description": "Platomico location id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Terminals available at the location"
          }
        },
        "tags": [
          "Integrations:V2:Revolut"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/sinqro/sync": {
      "post": {
        "operationId": "SinqroController_sync",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ]
      }
    },
    "/integrations/v2/contracts": {
      "get": {
        "operationId": "ContractsController_fetch",
        "summary": "List contracts",
        "description": "Returns the provider contracts configured for the current company (one contract per provider binding).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Company contracts"
          }
        },
        "tags": [
          "Contracts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "ContractsController_create",
        "summary": "Create a contract",
        "description": "Registers a new contract for the current company against a provider, including credentials (stored encrypted) and the authorization mode.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.CreateContract"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created contract"
          }
        },
        "tags": [
          "Contracts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/contracts/{id}/settings/operations": {
      "patch": {
        "operationId": "ContractsController_updateOperations",
        "summary": "Update operations settings",
        "description": "Toggle downstream operations (e.g. physical receipt printing, first/third-party delivery) for orders coming from this contract. Only the fields included in the body are updated.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Contract id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.UpdateOperationsSettings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated contract"
          }
        },
        "tags": [
          "Contracts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/contracts/{id}/active": {
      "patch": {
        "operationId": "ContractsController_setActive",
        "summary": "Enable or disable a contract",
        "description": "Toggles the contract active flag for the current company. Disabling makes the integration inert for its location(s) without deleting the contract or its credentials.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Contract id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.SetContractActive"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated contract"
          }
        },
        "tags": [
          "Contracts"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers": {
      "get": {
        "operationId": "ProvidersController_fetch",
        "summary": "List providers available to the current company",
        "description": "Returns global providers plus providers specifically scoped to this company.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Providers visible to the current company"
          }
        },
        "tags": [
          "Providers"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/bindings/{id}": {
      "delete": {
        "operationId": "BindingsController_delete",
        "summary": "Delete a binding",
        "description": "Permanently removes the binding from the company. Scoped by trace.companyId.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0",
              "type": "string"
            }
          },
          {
            "name": "companyId",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d1",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion result"
          }
        },
        "tags": [
          "Bindings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/bindings/bundle": {
      "post": {
        "operationId": "BindingsController_createBundle",
        "summary": "Create a BUNDLE binding (Square)",
        "description": "Maps (Platomico meal + step item pick) to a single Square ITEM. Used when a Platomico MEAL collapses into a Square ITEM with modifiers.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.CreateBundleBinding"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created BUNDLE binding"
          }
        },
        "tags": [
          "Bindings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/haddock/sync-catalog": {
      "post": {
        "operationId": "HaddockController_syncCatalog",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ]
      }
    },
    "/integrations/v2/events/subscriptions": {
      "post": {
        "operationId": "EventsController_toggleSubscription",
        "summary": "Toggle an event subscription on a contract",
        "description": "Enable or disable a specific event type for a contract, with optional per-location and per-source scoping. Empty locationsIds defaults to [\"*\"] (every location covered by the contract). Empty sources defaults to [\"*\"] (every upstream source); otherwise an allowlist matched case-insensitively against envelope.trace.source.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ToggleEventSubscriptionBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated contract"
          }
        },
        "tags": [
          "Integrations:V2:Events"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/events/logs": {
      "get": {
        "operationId": "EventsController_listLogs",
        "summary": "List event dispatch logs",
        "description": "Returns recent dispatch attempts for the current company, newest first.",
        "parameters": [
          {
            "name": "eventType",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "transactionId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "ISO 8601 lower bound",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "ISO 8601 upper bound",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Default 50, max 200",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of EventLog rows"
          }
        },
        "tags": [
          "Integrations:V2:Events"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/deliverect/register": {
      "post": {
        "operationId": "DeliverectController_register",
        "summary": "Register a Deliverect location and return the POS webhook URLs",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ]
      }
    },
    "/integrations/v2/providers/deliverect/locations": {
      "post": {
        "operationId": "DeliverectController_listLocations",
        "summary": "List the Deliverect locations reachable with our credentials",
        "description": "Returns the stores of a Deliverect account so an admin can map each Platomico location to its Deliverect one. Each entry reports the Platomico location Deliverect already has on file, so already-paired stores are visible. Credentials come from the body or, once a DELIVERECT contract exists, from that contract.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "example": {
                  "accountId": "6a354eaccf2a5c40b57e863c",
                  "clientId": "...",
                  "clientSecret": "..."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deliverect locations"
          }
        },
        "tags": [
          "Integrations:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/deliverect/channels": {
      "post": {
        "operationId": "DeliverectController_listChannels",
        "summary": "List the marketplaces Deliverect can route orders from",
        "description": "Names the marketplaces Deliverect can route orders from, so an operator can tell which of them a store is linked to. Reads the live table when credentials are available and falls back to the one shipped with the provider when they are not.",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/deliverect/locations/{locationId}/sync": {
      "post": {
        "operationId": "DeliverectController_requestManualSync",
        "summary": "Push a location menu to Deliverect on demand",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "path",
            "description": "Platomico location id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/deliverect/webhook/orders/{locationId}": {
      "post": {
        "operationId": "DeliverectController_receiveOrder",
        "summary": "Receive a Deliverect order for a location",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.ReceiveDeliverectOrderDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ]
      }
    },
    "/integrations/v2/providers/deliverect/sync-products/{locationId}": {
      "get": {
        "operationId": "DeliverectController_requestSyncProducts",
        "summary": "Push the location menu to Deliverect",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ]
      },
      "post": {
        "operationId": "DeliverectController_syncProducts",
        "summary": "Push the location menu to Deliverect",
        "parameters": [
          {
            "name": "locationId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2"
        ]
      }
    },
    "/integrations/v2/webhooks/deliveries": {
      "get": {
        "operationId": "WebhooksController_listDeliveryLog",
        "summary": "The delivery log",
        "description": "Every delivery of every webhook of the current company, newest first, with its retry state. Filter by webhookId, eventType, status (PENDING, DELIVERED, EXHAUSTED, CANCELLED), transactionId and a createdAt range.",
        "parameters": [
          {
            "name": "webhookId",
            "required": false,
            "in": "query",
            "description": "Only this webhook",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventType",
            "required": false,
            "in": "query",
            "schema": {
              "example": "transaction.created",
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "PENDING, DELIVERED, EXHAUSTED or CANCELLED",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "transactionId",
            "required": false,
            "in": "query",
            "description": "Exact transaction id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "required": false,
            "in": "query",
            "description": "ISO 8601 lower bound",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "ISO 8601 upper bound",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Default 1",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "description": "Default 25, max 100",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items, total, page, pageSize }"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks/deliveries/{deliveryId}": {
      "get": {
        "operationId": "WebhooksController_readDelivery",
        "summary": "One delivery",
        "description": "The delivery with its body as sent and every attempt made so far.",
        "parameters": [
          {
            "name": "deliveryId",
            "required": true,
            "in": "path",
            "description": "Delivery id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery detail"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks/deliveries/{deliveryId}/redeliver": {
      "post": {
        "operationId": "WebhooksController_redeliver",
        "summary": "Send a delivery again now",
        "description": "Sends the same body again immediately, whatever the delivery status and schedule. The retry ladder is not consumed; a 2xx closes the delivery as DELIVERED. 409 while an attempt is in flight.",
        "parameters": [
          {
            "name": "deliveryId",
            "required": true,
            "in": "path",
            "description": "Delivery id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery detail after the attempt"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks/deliveries/{deliveryId}/cancel": {
      "post": {
        "operationId": "WebhooksController_cancelDelivery",
        "summary": "Stop retrying a delivery",
        "description": "Closes a PENDING delivery as CANCELLED. 409 if it is not pending or an attempt is in flight.",
        "parameters": [
          {
            "name": "deliveryId",
            "required": true,
            "in": "path",
            "description": "Delivery id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery detail"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks": {
      "get": {
        "operationId": "WebhooksController_list",
        "summary": "List webhooks",
        "description": "Returns the custom webhooks of the current company, newest first. The signing secret is never included.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Webhooks"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "WebhooksController_create",
        "summary": "Create a webhook",
        "description": "Registers an HTTPS endpoint that receives a signed POST for each selected event. The response carries the signing secret; it is stored encrypted and can be read again through GET /:id/secret.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.CreateWebhook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created webhook, including its signing secret"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks/{id}": {
      "patch": {
        "operationId": "WebhooksController_update",
        "summary": "Update a webhook",
        "description": "Changes the name, URL, events, locations or active flag. Only the fields present in the body are written.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Webhook id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.UpdateWebhook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated webhook"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "WebhooksController_delete",
        "summary": "Delete a webhook",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Webhook id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, removed: true }"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks/{id}/secret": {
      "get": {
        "operationId": "WebhooksController_revealSecret",
        "summary": "Reveal the signing secret",
        "description": "Returns the secret used to sign deliveries, so a receiver can verify X-Platomico-Signature.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Webhook id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ secret }"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "WebhooksController_listDeliveries",
        "summary": "List recent deliveries",
        "description": "Recent deliveries to this webhook, newest first, each with its latest attempt flattened on top and its retry state.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Webhook id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Default 20, max 100",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deliveries"
          }
        },
        "tags": [
          "Integrations:V2:Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/loyalty/checkout/resolve": {
      "post": {
        "operationId": "LoyaltyController_resolveCheckout",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.CheckoutResolveRequestDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/loyalty/orders": {
      "post": {
        "operationId": "LoyaltyController_syncOrder",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.SyncLoyaltyOrderRequestDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/loyalty/orders/{externalOrderId}": {
      "delete": {
        "operationId": "LoyaltyController_voidOrder",
        "parameters": [
          {
            "name": "externalOrderId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Integrations:V2:Loyalty"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/providers/comeback/locations": {
      "post": {
        "operationId": "ComebackController_listLocations",
        "summary": "List the Comeback locations for a token",
        "description": "Returns the locations of the organization so an admin can map each Platomico location to its Comeback location. The token can be supplied in the body or, once a COMEBACK contract exists, reused from it.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "example": {
                  "token": "49d0d57f-..."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Comeback locations"
          }
        },
        "tags": [
          "Integrations:V2"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/integrations/v2/loyalty/settings": {
      "get": {
        "operationId": "LoyaltySettingsController_fetch",
        "summary": "Read the loyalty settings of the current company",
        "description": "Returns the earn rate and the reward on offer. A company that has never been configured gets the defaults the programme shipped with, so this never answers empty. Answers 404 for a company whose loyalty is not run by Platomico.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Loyalty settings"
          }
        },
        "tags": [
          "Loyalty settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "LoyaltySettingsController_update",
        "summary": "Change the loyalty settings of the current company",
        "description": "Sets the earn rate, the reward, or both — only the fields included are changed. The reward is sent whole. Its eligible ids are checked against the company menu and must be MEALs; the reward identifier is not settable, because a redemption in flight is keyed on it.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/integrations.UpdateLoyaltySettings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated loyalty settings"
          }
        },
        "tags": [
          "Loyalty settings"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/files/trim": {
      "get": {
        "operationId": "FilesController_trim",
        "summary": "Shorten a file URL",
        "description": "Converts a full storage URL into a short alias that can be embedded in emails or QRs. Public because short URLs are generated server-side during rendering.",
        "parameters": [
          {
            "name": "url",
            "required": true,
            "in": "query",
            "description": "Full file URL to trim",
            "schema": {
              "example": "https://cdn.platomico.com/some/very/long/key/receipt.pdf",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Shortened URL",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "url": "https://f.platomico.com/a1b2c3"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/mail/update-notification-status/{id}": {
      "get": {
        "operationId": "MailController_updateNotificationStatus",
        "summary": "Email open-tracking pixel",
        "description": "Serves a 1x1 PNG tracking pixel and marks the referenced notification as opened. Embedded in outgoing HTML emails.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Notification id encoded in the tracking URL",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "1x1 transparent PNG"
          }
        },
        "tags": [
          "Mails"
        ]
      }
    },
    "/common/notifications/subscribe": {
      "post": {
        "operationId": "NotificationsController_subscribe",
        "summary": "Subscribe a user to a notification channel",
        "description": "Opts a user in to a given (channel, userType) pair. If `isRequired` is true, the user cannot later unsubscribe.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.NotificationsPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription created"
          }
        },
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/notifications/unsubscribe": {
      "post": {
        "operationId": "NotificationsController_unsubscribe",
        "summary": "Unsubscribe a user from a notification channel",
        "description": "Opts a user out of a given (channel, userType) pair.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.NotificationsPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription removed"
          }
        },
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/notifications/templates": {
      "get": {
        "operationId": "TemplatesController_fetch",
        "summary": "Search notification templates",
        "description": "Returns templates for the signed-in user’s current company, filtered by any subset of NotificationTemplatePayload.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Matching templates"
          }
        },
        "tags": [
          "Notifications:Templates"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "TemplatesController_create",
        "summary": "Create a notification template",
        "description": "Creates a reusable template for the signed-in user’s current company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.NotificationTemplatePayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created template"
          }
        },
        "tags": [
          "Notifications:Templates"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "patch": {
        "operationId": "TemplatesController_update",
        "summary": "Update a notification template",
        "description": "Partially updates the template with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.NotificationsPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated template"
          }
        },
        "tags": [
          "Notifications:Templates"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "delete": {
        "operationId": "TemplatesController_deleteNotificationTemplate",
        "summary": "Delete a notification template",
        "description": "Permanently removes the template with the given id.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "query",
            "schema": {
              "example": "64f1b8a2c3d4e5f6a7b8c9d0",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          }
        },
        "tags": [
          "Notifications:Templates"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/print-jobs/pending": {
      "get": {
        "operationId": "PrintJobsController_pending",
        "summary": "List pending print jobs for the current device",
        "description": "Returns the jobs queued for the signed-in device’s company + location that are still waiting to be printed. The device polls this endpoint and acks after printing.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Pending jobs",
            "content": {
              "application/json": {
                "schema": {
                  "example": [
                    {
                      "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                      "url": "https://cdn.platomico.com/print-jobs/abc.png",
                      "receiverId": "64f1b8a2c3d4e5f6a7b8c9d1"
                    }
                  ]
                }
              }
            }
          }
        },
        "tags": [
          "PrintJobs"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/print-jobs/ack": {
      "post": {
        "operationId": "PrintJobsController_ack",
        "summary": "Acknowledge printed jobs",
        "description": "Marks the given job ids as PRINTED so they stop being returned by /pending.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ids"
                ],
                "properties": {
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "example": [
                      "64f1b8a2c3d4e5f6a7b8c9d0"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "acknowledged": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "PrintJobs"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/print-jobs/preview": {
      "post": {
        "operationId": "PrintJobsController_preview",
        "summary": "Preview a print template as an image",
        "description": "Compiles a print template with the given args and returns the rendered PNG inline. Used for thermal printer previews.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "template",
                  "args"
                ],
                "properties": {
                  "template": {
                    "type": "string",
                    "example": "ticket-kitchen"
                  },
                  "args": {
                    "type": "object",
                    "example": {
                      "orderId": "ord_123",
                      "items": [
                        {
                          "name": "Taco",
                          "qty": 2
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rendered ticket image",
            "content": {
              "image/png": {}
            }
          }
        },
        "tags": [
          "PrintJobs"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/health": {
      "get": {
        "operationId": "HealthController_check",
        "summary": "Service health check",
        "description": "Returns liveness/readiness details for common-service. Used by load balancers and uptime monitors.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Health details for each dependency",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "mongodb": {
                      "status": "up"
                    },
                    "redis": {
                      "status": "up"
                    },
                    "common-service": {
                      "status": "up"
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Health"
        ]
      }
    },
    "/common/forms": {
      "post": {
        "operationId": "FormsController_create",
        "summary": "Create a form",
        "description": "Creates a form definition for the signed-in user’s company. Submissions are routed to the listed receivers.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.CreateForm"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created form"
          }
        },
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/forms/submit": {
      "post": {
        "operationId": "FormsController_submit",
        "summary": "Submit a form",
        "description": "Submits values for a previously-created form. Triggers notifications to the form’s receivers.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.SubmitForm"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submission receipt"
          }
        },
        "tags": [
          "Forms"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/audit": {
      "get": {
        "operationId": "AuditTrailController_fetch",
        "summary": "Search the audit trail for the caller company",
        "description": "Requires the audit-log permission. Company scope always comes from the session; a companyIdentifier in the query is ignored.",
        "parameters": [
          {
            "name": "companyId",
            "required": false,
            "in": "query",
            "description": "Company scope. Forced to the caller company on the HTTP route; only the internal RPC may set it freely",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "description": "Filter by location",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "actorId",
            "required": false,
            "in": "query",
            "description": "Filter by the user who acted",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "actorType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "USER",
                "MEMBER",
                "CUSTOMER",
                "DEVICE",
                "API",
                "STAFF",
                "ENDPOINT",
                "SYSTEM"
              ],
              "type": "string"
            }
          },
          {
            "name": "action",
            "required": false,
            "in": "query",
            "description": "Exact action, or a prefix such as `users.` to match a whole domain",
            "schema": {
              "enum": [
                "users.user.invite",
                "users.user.update",
                "users.user.delete",
                "users.user.activate",
                "users.user.role-update",
                "users.user.password-update",
                "users.role.create",
                "users.role.update",
                "users.role.delete",
                "users.role.assign",
                "auth.api-key.create",
                "auth.api-key.revoke",
                "companies.company.update",
                "companies.company.billing-update",
                "locations.location.create",
                "locations.location.update",
                "locations.location.delete",
                "locations.location.status-update",
                "settings.setting.create",
                "settings.setting.update",
                "settings.setting.delete",
                "devices.device.create",
                "devices.device.update",
                "devices.device.delete",
                "endpoints.endpoint.create",
                "endpoints.endpoint.update",
                "endpoints.endpoint.delete",
                "schedules.schedule.update",
                "shifts.shift.create",
                "shifts.shift.update",
                "shifts.shift.delete",
                "orders.order.cancel",
                "orders.order.reassign",
                "payments.payment.refund",
                "payments.cash-drawer.adjust",
                "catalogue.product.create",
                "catalogue.product.update",
                "catalogue.product.delete",
                "catalogue.menu.create",
                "catalogue.menu.update",
                "catalogue.menu.delete",
                "catalogue.menu.publish",
                "catalogue.menu.discard",
                "catalogue.item.create",
                "catalogue.item.update",
                "catalogue.item.delete",
                "catalogue.meal.create",
                "catalogue.meal.update",
                "catalogue.meal.delete",
                "catalogue.modifier.create",
                "catalogue.modifier.update",
                "catalogue.modifier.delete",
                "catalogue.preparation.create",
                "catalogue.preparation.update",
                "catalogue.preparation.delete",
                "catalogue.step.create",
                "catalogue.step.update",
                "catalogue.step.delete",
                "catalogue.step.propagate",
                "catalogue.locale.create",
                "catalogue.locale.update",
                "catalogue.locale.bulk-upsert",
                "catalogue.visibility.update",
                "catalogue.visibility.bulk-update",
                "catalogue.visibility.publish",
                "supply.consumable.create",
                "supply.consumable.update",
                "supply.consumable.delete",
                "supply.provider.create",
                "supply.provider.update",
                "supply.provider.delete",
                "supply.measure.create",
                "supply.measure.update",
                "supply.measure.delete",
                "supply.purchase-order.create",
                "supply.purchase-order.update",
                "supply.purchase-order.delete",
                "supply.reception.create",
                "supply.reception.update",
                "supply.reception.delete",
                "supply.reception.confirm",
                "supply.reception.fix",
                "supply.reception.upload-delivery-note",
                "supply.stock-store.create",
                "supply.stock-store.update",
                "supply.stock-store.delete",
                "supply.consumption.track",
                "supply.consumption.retrack",
                "delivery.fee.create",
                "delivery.fee.update",
                "delivery.fee.delete",
                "delivery.order.create",
                "payments.discount.create",
                "payments.discount.update",
                "payments.discount.delete",
                "payments.fee.create",
                "payments.fee.update",
                "payments.tax.create",
                "payments.tax.update",
                "payments.flow.create",
                "payments.flow.update",
                "payments.flow.delete",
                "payments.table.create",
                "payments.table.update",
                "payments.cash-register.create",
                "payments.cash-register.open",
                "payments.cash-register.close",
                "payments.cash-register.track",
                "payments.cash-snapshot.update",
                "payments.cash-snapshot.fix",
                "payments.source.create",
                "marketing.subscriber.create",
                "payments.transaction.fix",
                "payments.platform.link-location",
                "payments.platform.link-domain",
                "payments.platform.link-reader",
                "payments.platform.link-subscription-price",
                "payments.platform.link-webhook",
                "payments.apple-pay.register-domain",
                "schedules.schedule.create",
                "schedules.schedule.delete",
                "shifts.template.create",
                "shifts.template.update",
                "shifts.template.delete",
                "shifts.template.restore",
                "shifts.absence.create",
                "shifts.absence.update",
                "shifts.absence.delete",
                "shifts.override.create",
                "shifts.override.update",
                "shifts.override.delete",
                "shifts.request.decide",
                "members.member.create",
                "members.member.update",
                "members.member.delete",
                "members.member.activate",
                "members.member.bulk-role-update",
                "loyalty.program.create",
                "loyalty.program.update",
                "loyalty.program.delete",
                "loyalty.reward.create",
                "loyalty.template.create",
                "loyalty.template.update",
                "loyalty.template.delete",
                "loyalty.color.create",
                "loyalty.benefit.create",
                "incidents.incident.create",
                "incidents.incident.update",
                "invoices.invoice.create",
                "delivery.fleet.update",
                "delivery.courier.invite",
                "delivery.courier.update",
                "delivery.courier.delete",
                "delivery.performance-threshold.update",
                "delivery.support-request.update",
                "orders.order.update",
                "releases.release.create",
                "stations.flow.upsert",
                "stations.flow.delete",
                "tasks.task.create",
                "tasks.task.update",
                "tasks.task.delete",
                "preferences.channel-groups.upsert",
                "onboarding.invite.seed",
                "integrations.integration.create",
                "integrations.binding.create",
                "integrations.binding.update",
                "integrations.binding.delete",
                "integrations.contract.create",
                "integrations.contract.update",
                "integrations.contract.activate",
                "integrations.provider.create",
                "integrations.event-subscription.toggle",
                "dashboard.page.view",
                "dashboard.resource.write",
                "dashboard.report.export",
                "dashboard.locations.select",
                "auth.session.sign-in",
                "auth.session.sign-in-failed",
                "auth.session.sign-out",
                "auth.session.company-switch",
                "auth.session.password-reset-request"
              ],
              "type": "string"
            }
          },
          {
            "name": "entityType",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "USER",
                "USER_ROLE",
                "API_KEY",
                "COMPANY",
                "LOCATION",
                "SETTING",
                "DEVICE",
                "ENDPOINT",
                "SCHEDULE",
                "SHIFT",
                "ORDER",
                "PAYMENT",
                "CASH_DRAWER",
                "PRODUCT",
                "SESSION",
                "PAGE",
                "RESOURCE",
                "REPORT",
                "MENU",
                "ITEM",
                "MEAL",
                "MODIFIER",
                "PREPARATION",
                "STEP",
                "LOCALE",
                "VISIBILITY",
                "CONSUMABLE",
                "PROVIDER",
                "MEASURE",
                "PURCHASE_ORDER",
                "RECEPTION",
                "STOCK_STORE",
                "CONSUMPTION",
                "DELIVERY_FEE",
                "DELIVERY_ORDER",
                "DISCOUNT",
                "FEE",
                "TAX",
                "PAYMENT_FLOW",
                "TABLE",
                "CASH_REGISTER",
                "CASH_SNAPSHOT",
                "PAYMENT_SOURCE",
                "SUBSCRIBER",
                "TRANSACTION",
                "PLATFORM_LINK",
                "APPLE_PAY_DOMAIN",
                "SHIFT_TEMPLATE",
                "SHIFT_ABSENCE",
                "SHIFT_OVERRIDE",
                "SHIFT_REQUEST",
                "MEMBER",
                "LOYALTY_PROGRAM",
                "LOYALTY_TEMPLATE",
                "LOYALTY_BENEFIT",
                "LOYALTY_REWARD",
                "LOYALTY_COLOR",
                "INCIDENT",
                "INVOICE",
                "DELIVERY_FLEET",
                "DELIVERY_COURIER",
                "SUPPORT_REQUEST",
                "PERFORMANCE_THRESHOLD",
                "APP_RELEASE",
                "STATIONS_FLOW",
                "TASK",
                "CHANNEL_GROUPS",
                "ONBOARDING_INVITE",
                "INTEGRATION",
                "INTEGRATION_BINDING",
                "INTEGRATION_CONTRACT",
                "INTEGRATION_PROVIDER",
                "EVENT_SUBSCRIPTION"
              ],
              "type": "string"
            }
          },
          {
            "name": "entityIdentifier",
            "required": false,
            "in": "query",
            "description": "Filter by the affected record",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "result",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "SUCCESS",
                "FAILURE",
                "DENIED"
              ],
              "type": "string"
            }
          },
          {
            "name": "channel",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "DASHBOARD",
                "API",
                "DEVICE",
                "INTERNAL",
                "SCHEDULED"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "schema": {
              "example": "2026-08-01T00:00:00.000Z",
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "schema": {
              "example": "2026-08-25T23:59:59.999Z",
              "type": "string"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "schema": {
              "example": 0,
              "type": "number"
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Capped at 200",
            "schema": {
              "example": 50,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching audit records, newest first"
          }
        },
        "tags": [
          "Audit"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/audit/catalogue": {
      "get": {
        "operationId": "AuditTrailController_fetchCatalogue",
        "summary": "The catalogue of audited actions",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Action key, entity and retention class"
          }
        },
        "tags": [
          "Audit"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/audit/dashboard": {
      "post": {
        "operationId": "AuditTrailController_recordDashboardAction",
        "summary": "Record a dashboard action for the calling user",
        "description": "Actor, company, IP and user agent are taken from the request, never from the body. Only dashboard.* and the two session actions the dashboard witnesses are accepted.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.RecordDashboardAction"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recorded"
          }
        },
        "tags": [
          "Audit"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/ai": {
      "post": {
        "operationId": "AiController_onMessage",
        "summary": "Send a message to an AI model",
        "description": "Routes the message through the configured brain/tools/contexts of the target model and returns the assistant reply (creating a new chat if chatId is omitted).",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.OnMessage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Assistant reply with the updated chat context"
          }
        },
        "tags": [
          "AI"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/ai/brain": {
      "post": {
        "operationId": "BrainController_create",
        "summary": "Create a brain",
        "description": "Creates a brain (persona + role + backing model) attached to the signed-in user’s current company.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.CreateBrain"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created brain"
          }
        },
        "tags": [
          "AI:Brain"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/ai/context": {
      "post": {
        "operationId": "ContextController_create",
        "summary": "Create an AI context",
        "description": "Creates a reusable knowledge block (cases + solutions) that can be attached to an AI model via its trace.modelId.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.CreateContext"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created context"
          }
        },
        "tags": [
          "AI:Context"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/ai/tools": {
      "post": {
        "operationId": "ToolsController_create",
        "summary": "Create a tool",
        "description": "Registers a tool the AI can call. The tool is backed by an internal RPC and typed input/output schemas.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.CreateTool"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created tool"
          }
        },
        "tags": [
          "AI:Tools"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/ai/model": {
      "post": {
        "operationId": "ModelController_createModel",
        "summary": "Create an AI model",
        "description": "Creates an AI model container. Brains, tools and contexts are attached separately via their own endpoints.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.CreateModel"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created model"
          }
        },
        "tags": [
          "AI:Models"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/claude/translate": {
      "post": {
        "operationId": "ClaudeController_translate",
        "summary": "Translate catalog strings",
        "description": "Translates a batch of catalog strings (dish/meal/section names and descriptions) from a source language to a target language using Claude. Ids are preserved so the caller can map results back onto its locale documents. Used by the admin Locales settings tab to auto-translate a menu into a new language.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.TranslateLocalesPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The translated entries, keyed by the same ids.",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "translations": [
                      {
                        "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                        "text": "Hamburger Classico"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Claude"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/menu-import": {
      "post": {
        "operationId": "MenuImportController_start",
        "summary": "Start a menu import (async)",
        "description": "Given a restaurant name + location, kicks off a background job that finds the menu on the web, structures it, uploads images to S3 and creates items/meals/menu in supply-chain. Returns a jobId immediately — poll GET /:jobId for progress and streamed results.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/common.MenuImportPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The started job.",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "jobId": "01J...",
                    "status": "researching"
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Menu Import"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/menu-import/{jobId}": {
      "get": {
        "operationId": "MenuImportController_status",
        "summary": "Poll a menu-import job",
        "description": "Returns the evolving job state: status, restaurant, planned totals, items/meals created so far, the menu, and a live activity log. Scoped to the authenticated company.",
        "parameters": [
          {
            "name": "jobId",
            "required": true,
            "in": "path",
            "schema": {
              "example": "01J...",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The current job state."
          }
        },
        "tags": [
          "Menu Import"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/common/menu-import/{jobId}/continue": {
      "post": {
        "operationId": "MenuImportController_continueJob",
        "summary": "Resume a bot-flagged import",
        "description": "Call after the user has unlocked the live browser (solved a CAPTCHA / dismissed a bot wall) for a job in the needsInteraction state. Releases discovery to resume the scrape.",
        "parameters": [
          {
            "name": "jobId",
            "required": true,
            "in": "path",
            "schema": {
              "example": "01J...",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "example": {
                    "ok": true
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Menu Import"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "authentication.Code": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Verification or exchange code",
            "example": "a1b2c3d4"
          }
        },
        "required": [
          "code"
        ]
      },
      "authentication.SignUpFromDevice": {
        "type": "object",
        "properties": {
          "company": {
            "type": "object",
            "description": "Company billing and identity details",
            "example": {
              "businessName": "Tacos Platomico SL",
              "taxId": "B12345678",
              "address": "Calle Mayor 10",
              "state": "Madrid",
              "city": "Madrid",
              "zipCode": "28013"
            }
          },
          "location": {
            "type": "object",
            "description": "Physical location where the device operates",
            "example": {
              "coordinates": [
                -3.7038,
                40.4168
              ],
              "timezone": "Europe/Madrid",
              "name": "Tacos Platomico - Sol",
              "country": "ES",
              "address": "Calle Mayor 10",
              "locality": "Sol",
              "city": "Madrid",
              "zipCode": "28013"
            }
          },
          "device": {
            "type": "object",
            "description": "Device metadata",
            "example": {
              "type": "POS",
              "provider": "iPad"
            }
          }
        },
        "required": [
          "company",
          "location",
          "device"
        ]
      },
      "authentication.SignUpFromWeb": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "New user's email address",
            "example": "user@platomico.com"
          },
          "password": {
            "type": "string",
            "description": "Password to set for the new account",
            "example": "correcthorsebatterystaple"
          },
          "name": {
            "type": "string",
            "description": "User's full name",
            "example": "Jane Doe"
          },
          "verificationToken": {
            "type": "string",
            "description": "Token issued by the email verification step",
            "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
          }
        },
        "required": [
          "email",
          "password",
          "name",
          "verificationToken"
        ]
      },
      "authentication.ExchangeCustomerSession": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name under which to exchange the session",
            "example": "Jane Doe"
          },
          "companyId": {
            "type": "string",
            "description": "Target company ID",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "name",
          "companyId"
        ]
      },
      "authentication.MemberCode": {
        "type": "object",
        "properties": {
          "code": {
            "type": "number",
            "description": "Numeric member sign-in code",
            "example": 482913
          }
        },
        "required": [
          "code"
        ]
      },
      "authentication.CreateRemoteAccessCode": {
        "type": "object",
        "properties": {
          "endpoint": {
            "type": "string",
            "description": "Target endpoint domain the remote access code will authorize",
            "example": "order.platomico.com"
          },
          "payload": {
            "type": "object",
            "description": "Arbitrary payload associated with the access code",
            "example": {
              "action": "open-cash-register",
              "cashRegisterId": "cr_123"
            }
          }
        },
        "required": [
          "endpoint",
          "payload"
        ]
      },
      "authentication.AccessCode": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Remote access code",
            "example": "a1b2c3d4"
          }
        },
        "required": [
          "code"
        ]
      },
      "authentication.CustomerLoginPayload": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Customer's email address",
            "example": "customer@example.com"
          },
          "name": {
            "type": "string",
            "description": "Customer's first name",
            "example": "Jane"
          },
          "lastname": {
            "type": "string",
            "description": "Customer's last name",
            "example": "Doe"
          },
          "birthdate": {
            "format": "date-time",
            "type": "string",
            "description": "Customer's date of birth",
            "example": "1990-05-20"
          },
          "phone": {
            "type": "object",
            "description": "Customer's phone number with country prefix",
            "example": {
              "prefix": "+34",
              "number": "600123456"
            }
          }
        },
        "required": [
          "email",
          "name"
        ]
      },
      "authentication.Credentials": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "User's email address",
            "example": "user@platomico.com"
          },
          "password": {
            "type": "string",
            "description": "User's password",
            "example": "correcthorsebatterystaple"
          }
        },
        "required": [
          "email",
          "password"
        ]
      },
      "authentication.Email": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Email address",
            "example": "user@platomico.com"
          }
        },
        "required": [
          "email"
        ]
      },
      "authentication.MemberSignIn": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Member's email address",
            "example": "member@platomico.com"
          },
          "code": {
            "type": "number",
            "description": "Numeric member sign-in code",
            "example": 482913
          }
        },
        "required": [
          "email",
          "code"
        ]
      },
      "authentication.DeviceCode": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Device pairing code",
            "example": "ABC123"
          }
        },
        "required": [
          "code"
        ]
      },
      "authentication.SmsPayload": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Verification code sent to the user (empty when requesting a new code)",
            "example": "482913"
          },
          "phone": {
            "type": "object",
            "description": "Phone number with country prefix",
            "example": {
              "prefix": "+34",
              "number": "600123456"
            }
          },
          "provider": {
            "type": "string",
            "description": "SMS gateway to use",
            "enum": [
              "TWILIO",
              "NEXMO"
            ],
            "example": "TWILIO"
          },
          "token": {
            "type": "string",
            "description": "Anti-abuse token (e.g. reCAPTCHA) when requesting a new code",
            "example": "03AGdBq27..."
          }
        },
        "required": [
          "code",
          "phone",
          "provider"
        ]
      },
      "authentication.CreateDeviceCode": {
        "type": "object",
        "properties": {}
      },
      "authentication.VerifyPermission": {
        "type": "object",
        "properties": {}
      },
      "authentication.CreateSecret": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Company the secret belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "contractId": {
            "type": "string",
            "description": "Optional contract (provider binding) the secret belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "provider": {
            "type": "string",
            "description": "Provider that owns the secret",
            "example": "stripe"
          },
          "value": {
            "type": "string",
            "description": "Secret value (will be encrypted at rest)",
            "example": "sk_live_...redacted..."
          },
          "tag": {
            "type": "string",
            "description": "Tag to disambiguate secrets of the same provider",
            "example": "primary"
          }
        },
        "required": [
          "companyId",
          "provider",
          "value",
          "tag"
        ]
      },
      "authentication.FetchSecret": {
        "type": "object",
        "properties": {
          "tag": {
            "type": "string",
            "description": "Optional tag to disambiguate secrets of the same provider",
            "example": "primary"
          },
          "companyId": {
            "type": "string",
            "description": "Company the secret belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "provider": {
            "type": "string",
            "description": "Provider that owns the secret",
            "example": "stripe"
          }
        },
        "required": [
          "companyId",
          "provider"
        ]
      },
      "authentication.CreateApiKey": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Operator-facing label",
            "example": "Zapier"
          },
          "services": {
            "type": "array",
            "description": "Gateway prefixes this key may call",
            "example": [
              "operations",
              "payments"
            ],
            "items": {
              "type": "string",
              "enum": [
                "auth",
                "operations",
                "payments",
                "supply-chain",
                "integrations",
                "common"
              ]
            }
          },
          "mode": {
            "type": "string",
            "description": "READ keys may only issue GET and HEAD",
            "example": "READ",
            "enum": [
              "READ",
              "WRITE"
            ]
          },
          "locationsIds": {
            "description": "Locations this key may name. [] or ['*'] means every one.",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expiresAt": {
            "type": "string",
            "description": "ISO date after which the key stops working. Absent = never.",
            "example": "2027-01-01T00:00:00.000Z"
          }
        },
        "required": [
          "name",
          "services",
          "mode"
        ]
      },
      "authentication.UpdateApiKey": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Zapier (staging)"
          },
          "services": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "auth",
                "operations",
                "payments",
                "supply-chain",
                "integrations",
                "common"
              ]
            }
          },
          "mode": {
            "type": "string",
            "enum": [
              "READ",
              "WRITE"
            ]
          },
          "locationsIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expiresAt": {
            "type": "string",
            "description": "ISO date, or null to clear the expiry"
          },
          "active": {
            "type": "boolean",
            "description": "Pause a key without revoking it"
          }
        }
      },
      "operations.UpdateSettings": {
        "type": "object",
        "properties": {
          "image": {
            "type": "object",
            "description": "New logo/image to upload as a base64 + extension tuple",
            "example": {
              "base64": "iVBORw0KGgoAAAANSUhEUgAAAAUA...",
              "ext": "png"
            }
          },
          "color": {
            "type": "string",
            "description": "Primary brand color as a hex string",
            "example": "#FF6600"
          },
          "name": {
            "type": "string",
            "description": "Company display name",
            "example": "Tacos Platomico"
          },
          "type": {
            "type": "string",
            "description": "Company business type (e.g. RESTAURANT, RETAIL)",
            "example": "RESTAURANT"
          },
          "billing": {
            "type": "object",
            "description": "Billing information to update",
            "example": {
              "businessName": "Tacos Platomico SL",
              "addresses": [
                {
                  "address": "Calle Mayor 10",
                  "city": "Madrid",
                  "state": "Madrid",
                  "country": "ES",
                  "zipCode": "28013"
                }
              ]
            }
          },
          "settings": {
            "type": "object",
            "description": "Company-level settings. `visibility` holds per-app page visibility overrides keyed by route path; each provided app map replaces that app's stored map wholesale. Fail-open: only explicit false hides.",
            "example": {
              "allowClockWithoutShift": true,
              "defaultLanguage": "ES",
              "visibility": {
                "analytics": {
                  "/analytics/sales": false
                }
              },
              "notifications": {
                "orderTrackingSms": true
              },
              "reporting": {
                "dayStartMinute": 360,
                "dayEndMinute": 360,
                "timezone": "Europe/Madrid"
              }
            }
          }
        }
      },
      "operations.CreateClientCompany": {
        "type": "object",
        "properties": {
          "businessName": {
            "type": "string",
            "description": "Legal/business name of the client company"
          },
          "taxId": {
            "type": "string",
            "description": "Tax id (CIF/NIF)"
          },
          "country": {
            "type": "string",
            "description": "ISO country code"
          },
          "address": {
            "type": "string",
            "description": "Billing address line"
          },
          "city": {
            "type": "string",
            "description": "City"
          },
          "contactEmail": {
            "type": "string",
            "description": "Contact email"
          },
          "contactPhone": {
            "type": "string",
            "description": "Contact phone"
          }
        },
        "required": [
          "businessName"
        ]
      },
      "operations.UpdateClientCompany": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "os company id to update (deal.clientCompanyIdentifier)"
          },
          "businessName": {
            "type": "string"
          },
          "taxId": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "contactEmail": {
            "type": "string"
          },
          "contactPhone": {
            "type": "string"
          }
        },
        "required": [
          "companyId"
        ]
      },
      "operations.CreateCompany": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Primary owner email for the new company",
            "example": "owner@platomico.com"
          },
          "country": {
            "type": "string",
            "description": "Country where the company operates",
            "example": "ES"
          },
          "businessName": {
            "type": "string",
            "description": "Legal business name of the company",
            "example": "Tacos Platomico SL"
          },
          "taxId": {
            "type": "string",
            "description": "Company tax identifier (CIF/NIF/VAT)",
            "example": "B12345678"
          },
          "address": {
            "type": "string",
            "description": "Billing street address",
            "example": "Calle Mayor 10"
          },
          "state": {
            "type": "string",
            "description": "Billing state / region",
            "example": "Madrid"
          },
          "city": {
            "type": "string",
            "description": "Billing city",
            "example": "Madrid"
          },
          "zipCode": {
            "type": "string",
            "description": "Billing postal code",
            "example": "28013"
          }
        },
        "required": [
          "email",
          "businessName",
          "taxId",
          "address",
          "state",
          "city",
          "zipCode"
        ]
      },
      "operations.UpdateStatus": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string",
            "description": "Provider account id to identify the company",
            "example": "acct_1NbcD2K1a2B3cD4E"
          },
          "status": {
            "type": "string",
            "description": "New onboarding status for the company",
            "enum": [
              "PENDING",
              "IN_PROCESS",
              "COMPLETED"
            ],
            "example": "COMPLETED"
          }
        },
        "required": [
          "accountId",
          "status"
        ]
      },
      "operations.Role": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Role display name",
            "example": "Rider"
          },
          "type": {
            "type": "string",
            "description": "Role type / category slug",
            "example": "user:courier"
          },
          "permissions": {
            "description": "Permission strings granted by the role",
            "example": [
              "read:users",
              "read:orders:accepted",
              "create:offers",
              "accept:offers"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean",
            "description": "Whether the role can currently be assigned / used",
            "example": true
          },
          "visible": {
            "type": "boolean",
            "description": "Whether the role is shown in selection lists",
            "example": true
          },
          "isSystem": {
            "type": "boolean",
            "description": "Whether the role was seeded from the default catalog (system role)",
            "example": false
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata (company, locations)",
            "example": {
              "companyId": "64f1b8a2c3d4e5f6a7b8c9c0",
              "locationsIds": [
                "*"
              ]
            }
          }
        },
        "required": [
          "name",
          "type",
          "permissions",
          "trace"
        ]
      },
      "operations.UpdateRole": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Role id",
            "example": "69ca70599588542b854b5503"
          },
          "name": {
            "type": "string",
            "description": "Updated name",
            "example": "Rider"
          },
          "type": {
            "type": "string",
            "description": "Updated type",
            "example": "user:courier"
          },
          "permissions": {
            "description": "Updated permission strings",
            "example": [
              "read:users",
              "accept:offers"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean",
            "description": "Updated active state",
            "example": true
          },
          "visible": {
            "type": "boolean",
            "description": "Updated visibility",
            "example": true
          }
        },
        "required": [
          "id"
        ]
      },
      "operations.OwnPhone": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "description": "Dial code",
            "example": "+34"
          },
          "number": {
            "type": "string",
            "description": "National number, without the dial code",
            "example": "654110194"
          }
        }
      },
      "operations.UpdateOwnUser": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Updated full name",
            "example": "Maria Gomez"
          },
          "phone": {
            "description": "Updated phone, split so the dial code never counts towards the national number length",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.OwnPhone"
              }
            ]
          },
          "avatar": {
            "type": "string",
            "description": "Updated avatar URL",
            "example": "https://example.com/avatar.png"
          }
        }
      },
      "operations.ChangeOwnPassword": {
        "type": "object",
        "properties": {
          "currentPassword": {
            "type": "string",
            "description": "Current password",
            "example": "currentSecret123"
          },
          "newPassword": {
            "type": "string",
            "description": "New password",
            "example": "newSecret123"
          }
        },
        "required": [
          "currentPassword",
          "newPassword"
        ]
      },
      "operations.NotificationChannel": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "operations.UpdateOwnNotifications": {
        "type": "object",
        "properties": {
          "closingSummary": {
            "$ref": "#/components/schemas/operations.NotificationChannel"
          },
          "lowStock": {
            "$ref": "#/components/schemas/operations.NotificationChannel"
          }
        }
      },
      "operations.InviteUser": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Invitee full name",
            "example": "Maria Gomez"
          },
          "email": {
            "type": "string",
            "description": "Invitee email address",
            "example": "maria@tacosplatomico.com"
          },
          "role": {
            "type": "string",
            "description": "Role the invitee will assume once they accept",
            "example": "Manager"
          },
          "roleId": {
            "type": "string",
            "description": "Page-access profile id (users/roles). Optional.",
            "example": "69ca70599588542b854b5503"
          },
          "locationIds": {
            "description": "Location ids the invitee may see, on top of the access profile. Empty or omitted means every location. Only accepted when the invitee stays in the active company.",
            "example": [
              "69ca70599588542b854b5504"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "companiesIds": {
            "description": "Companies the invitee will reach. One id means that company and its sub-companies; several ids mean exactly those. Omitted falls back to the active company.",
            "example": [
              "661ea12cd947fa93eb0cad68",
              "667458a52c445d283fa801b6"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locale": {
            "type": "string",
            "description": "Locale for the invitation email (es or en; falls back to es)",
            "example": "es"
          }
        },
        "required": [
          "name",
          "email",
          "role",
          "locale"
        ]
      },
      "operations.CreateUser": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Company the user will be attached to",
            "example": "64f1b8a2c3d4e5f6a7b8c9c0"
          },
          "email": {
            "type": "string",
            "description": "Email address of the new user",
            "example": "user@platomico.com"
          },
          "name": {
            "type": "string",
            "description": "User full name",
            "example": "Maria Gomez"
          },
          "role": {
            "type": "string",
            "description": "Role assigned to the user (Admin, Manager, Cashier, ...)",
            "example": "Admin"
          }
        },
        "required": [
          "companyId",
          "email",
          "name",
          "role"
        ]
      },
      "operations.Credentials": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "User's email address",
            "example": "user@platomico.com"
          },
          "password": {
            "type": "string",
            "description": "User's password",
            "example": "correcthorsebatterystaple"
          }
        },
        "required": [
          "email",
          "password"
        ]
      },
      "operations.FetchPaymentFromTool": {
        "type": "object",
        "properties": {}
      },
      "operations.UserRole": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Finance",
            "description": "Display name of the role"
          },
          "permissions": {
            "example": [
              "/analytics/sales",
              "/analytics/finance"
            ],
            "description": "Route paths this role may open. Anything not listed is hidden and blocked.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locationIds": {
            "example": [
              "69ca70599588542b854b5504"
            ],
            "description": "Location ids this role may see. Empty or absent means every location in the company, including ones created later; a non-empty list narrows the session to exactly those.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean",
            "example": true
          },
          "visible": {
            "type": "boolean",
            "example": true
          }
        },
        "required": [
          "name",
          "permissions"
        ]
      },
      "operations.UpdateUserRole": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "69ca70599588542b854b5503"
          },
          "name": {
            "type": "string",
            "example": "Finance"
          },
          "permissions": {
            "example": [
              "/analytics/sales"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locationIds": {
            "example": [
              "69ca70599588542b854b5504"
            ],
            "description": "Replaces the whole location list. Send `[]` to widen the role back to every location.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean",
            "example": true
          },
          "visible": {
            "type": "boolean",
            "example": true
          }
        },
        "required": [
          "id"
        ]
      },
      "operations.CreateLocation": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Location name",
            "example": "Tacos Platomico - Sol"
          },
          "status": {
            "type": "string",
            "description": "Operational status of the location",
            "enum": [
              "OPERATIONAL",
              "CLOSED"
            ],
            "example": "OPERATIONAL"
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: parent company, optional SKU and coordinates",
            "example": {
              "sku": "SOL01",
              "companyId": "64f1b8a2c3d4e5f6a7b8c9c0",
              "coordinates": [
                -3.7038,
                40.4168
              ]
            }
          },
          "settings": {
            "type": "object",
            "description": "Location settings (currency, timezone, address, branding)",
            "example": {
              "currency": "EUR",
              "timezone": "Europe/Madrid",
              "location": {
                "country": "ES",
                "address": "Calle Mayor 10",
                "city": "Madrid",
                "zipCode": "28013"
              }
            }
          },
          "knownAs": {
            "description": "External provider identifiers linked to this location",
            "example": [
              {
                "provider": "square",
                "id": "sq_loc_abc"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "businessName": {
            "type": "string",
            "description": "Legal business name for the location",
            "example": "Tacos Platomico SL"
          }
        },
        "required": [
          "name",
          "status",
          "trace",
          "businessName"
        ]
      },
      "operations.CreateLocationV2": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Location name",
            "example": "Tacos Platomico - Sol"
          },
          "status": {
            "type": "string",
            "description": "Operational status of the location",
            "enum": [
              "OPERATIONAL",
              "CLOSED"
            ],
            "example": "OPERATIONAL"
          },
          "businessName": {
            "type": "string",
            "description": "Legal business name for the location",
            "example": "Tacos Platomico SL"
          },
          "skipSku": {
            "type": "boolean",
            "description": "Skip auto-generating a SKU for this location",
            "example": false
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata",
            "example": {
              "companyId": "64f1b8a2c3d4e5f6a7b8c9c0",
              "coordinates": [
                -3.7038,
                40.4168
              ]
            }
          },
          "settings": {
            "type": "object",
            "description": "Location settings (currency, timezone, address, branding, workdays)",
            "example": {
              "currency": "EUR",
              "timezone": "Europe/Madrid",
              "location": {
                "country": "ES",
                "address": "Calle Mayor 10",
                "city": "Madrid",
                "zipCode": "28013"
              },
              "tickets": {
                "receipt": true,
                "kitchenReceipt": false
              },
              "workdays": {
                "mon": [
                  {
                    "from": "09:00",
                    "to": "23:00"
                  }
                ],
                "tue": [
                  {
                    "from": "09:00",
                    "to": "23:00"
                  }
                ]
              }
            }
          },
          "knownAs": {
            "description": "External provider identifiers linked to this location",
            "example": [
              {
                "provider": "square",
                "id": "sq_loc_abc"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "status",
          "businessName",
          "trace"
        ]
      },
      "operations.UpdateWorkdaysDto": {
        "type": "object",
        "properties": {
          "locationIds": {
            "description": "Locations to apply the workdays schedule to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "workdays": {
            "type": "object",
            "description": "Opening hours keyed by weekday. Keys are \"0\"-\"6\" with \"0\" = Sunday, matching Date.getDay(). A range whose `to` is not after its `from` closes the NEXT day (e.g. 22:00 → 02:00).",
            "example": {
              "0": [
                {
                  "from": "10:00",
                  "to": "22:00"
                }
              ],
              "1": [
                {
                  "from": "09:00",
                  "to": "23:00"
                }
              ],
              "2": [
                {
                  "from": "09:00",
                  "to": "23:00"
                }
              ],
              "3": [
                {
                  "from": "09:00",
                  "to": "23:00"
                }
              ],
              "4": [
                {
                  "from": "09:00",
                  "to": "23:00"
                }
              ],
              "5": [
                {
                  "from": "09:00",
                  "to": "01:00"
                }
              ],
              "6": [
                {
                  "from": "10:00",
                  "to": "01:00"
                }
              ]
            }
          },
          "days": {
            "description": "Restrict the write to these day keys. Omit to replace the whole week (the original behaviour). A day listed here but absent from `workdays` is cleared. The dashboard sends only the days the operator edited, so that editing several locations through one merged week cannot rewrite days nobody touched.",
            "example": [
              "1",
              "6"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationIds",
          "workdays"
        ]
      },
      "operations.DeliveryLiveTimerColumnPair": {
        "type": "object",
        "properties": {
          "soonMinutes": {
            "type": "number",
            "description": "Minutes after column entry when the card starts shifting toward red. -1 disables the warning.",
            "example": 5
          },
          "lateMinutes": {
            "type": "number",
            "description": "Minutes after column entry when the card reaches full red. -1 disables.",
            "example": 10
          }
        },
        "required": [
          "soonMinutes",
          "lateMinutes"
        ]
      },
      "operations.DeliveryLiveTimerColumns": {
        "type": "object",
        "properties": {
          "enPreparacion": {
            "$ref": "#/components/schemas/operations.DeliveryLiveTimerColumnPair"
          },
          "esperandoRecogida": {
            "$ref": "#/components/schemas/operations.DeliveryLiveTimerColumnPair"
          },
          "enReparto": {
            "$ref": "#/components/schemas/operations.DeliveryLiveTimerColumnPair"
          }
        },
        "required": [
          "enPreparacion",
          "esperandoRecogida",
          "enReparto"
        ]
      },
      "operations.DeliveryLiveTimers": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the visualization is active"
          },
          "showItemCountInline": {
            "type": "boolean",
            "description": "Whether the order id should be displayed alongside the count of non-meal items (e.g. \"AB12 (3 items)\")."
          },
          "itemCountMode": {
            "type": "string",
            "description": "How to count items: \"topLevel\" treats every line as one item (meals included); \"expandMeals\" walks meal steps and counts inner items × meal quantity.",
            "enum": [
              "topLevel",
              "expandMeals"
            ],
            "default": "topLevel"
          },
          "columns": {
            "$ref": "#/components/schemas/operations.DeliveryLiveTimerColumns"
          }
        },
        "required": [
          "enabled",
          "columns"
        ]
      },
      "operations.UpdateDeliveryLiveTimersDto": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "timers": {
            "$ref": "#/components/schemas/operations.DeliveryLiveTimers"
          }
        },
        "required": [
          "locationId",
          "timers"
        ]
      },
      "operations.UpdateTicketsDto": {
        "type": "object",
        "properties": {
          "locationIds": {
            "description": "Locations to apply the ticket settings to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tickets": {
            "type": "object",
            "description": "Ticket printing flags",
            "example": {
              "receipt": true,
              "kitchenReceipt": false
            }
          }
        },
        "required": [
          "locationIds",
          "tickets"
        ]
      },
      "operations.UpdateAutoPrintDto": {
        "type": "object",
        "properties": {
          "locationIds": {
            "description": "Locations to apply the auto-print settings to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "autoPrint": {
            "type": "object",
            "description": "Orders that must NOT print automatically. Both lists are deny lists: absent or empty means every order auto-prints.",
            "example": {
              "disabledSources": [
                "WEB",
                "KIOSK"
              ],
              "disabledDevicesIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ]
            }
          }
        },
        "required": [
          "locationIds",
          "autoPrint"
        ]
      },
      "operations.UpdatePosDto": {
        "type": "object",
        "properties": {
          "locationIds": {
            "description": "Locations to apply the POS settings to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "pos": {
            "type": "object",
            "description": "POS behaviour flags. autoComplete: when true, pressing \"Done\" completes the order immediately; when false, it advances through remaining meal steps and only completes on the last one. visibility: per-location show/hide flags for POS menu-bar buttons and settings-hub entries (absent/true = shown, false = hidden).",
            "example": {
              "autoComplete": true,
              "visibility": {
                "menu": {
                  "cashRegister": true,
                  "shifts": true,
                  "tables": true
                },
                "settings": {
                  "cash": true,
                  "orders": true,
                  "tables": true,
                  "shifts": true,
                  "general": true,
                  "devices": true
                }
              }
            }
          }
        },
        "required": [
          "locationIds",
          "pos"
        ]
      },
      "operations.UpdateOrderState": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Order identifier to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2"
          },
          "state": {
            "type": "string",
            "description": "New order state",
            "enum": [
              "PENDING",
              "IN_PROCESS",
              "COMPLETED",
              "CANCELLED"
            ],
            "example": "IN_PROCESS"
          }
        },
        "required": [
          "orderId",
          "state"
        ]
      },
      "operations.MarkOrderSeen": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Order rendered on the KDS screen for the first time",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "orderId"
        ]
      },
      "operations.AdvanceOrderStation": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Order to move along its SEQUENTIAL stations-flow route",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "direction": {
            "type": "string",
            "description": "FORWARD (default) moves the ticket to the next station of its route; BACK recalls it to the previous one (undo).",
            "enum": [
              "FORWARD",
              "BACK"
            ],
            "example": "FORWARD"
          }
        },
        "required": [
          "orderId"
        ]
      },
      "operations.UpdateOrderItemReady": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Order identifier whose item ready flag is being updated",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2"
          },
          "target": {
            "type": "string",
            "description": "Which slot of the order is being toggled. Determines which other indices are required.",
            "enum": [
              "ITEM",
              "ITEM_MODIFIER",
              "MEAL_STEP",
              "MEAL_STEP_MODIFIER"
            ],
            "example": "ITEM"
          },
          "itemIndex": {
            "type": "number",
            "description": "Index of the item inside Order.items",
            "example": 0
          },
          "stepIndex": {
            "type": "number",
            "description": "Index of the meal step inside items[itemIndex].steps. Required for MEAL_STEP and MEAL_STEP_MODIFIER.",
            "example": 0
          },
          "modifierIndex": {
            "type": "number",
            "description": "Index of the modifier. Required for ITEM_MODIFIER and MEAL_STEP_MODIFIER.",
            "example": 0
          },
          "ready": {
            "type": "boolean",
            "description": "Desired ready value. The call is idempotent.",
            "example": true
          }
        },
        "required": [
          "orderId",
          "target",
          "itemIndex",
          "ready"
        ]
      },
      "operations.OrderItemReadyChange": {
        "type": "object",
        "properties": {
          "target": {
            "type": "string",
            "description": "Which slot of the order is being toggled. Determines which other indices are required.",
            "enum": [
              "ITEM",
              "ITEM_MODIFIER",
              "MEAL_STEP",
              "MEAL_STEP_MODIFIER"
            ],
            "example": "ITEM"
          },
          "itemIndex": {
            "type": "number",
            "description": "Index of the item inside Order.items",
            "example": 0
          },
          "stepIndex": {
            "type": "number",
            "description": "Index of the meal step inside items[itemIndex].steps. Required for MEAL_STEP and MEAL_STEP_MODIFIER.",
            "example": 0
          },
          "modifierIndex": {
            "type": "number",
            "description": "Index of the modifier. Required for ITEM_MODIFIER and MEAL_STEP_MODIFIER.",
            "example": 0
          },
          "ready": {
            "type": "boolean",
            "description": "Desired ready value. The change is idempotent.",
            "example": true
          }
        },
        "required": [
          "target",
          "itemIndex",
          "ready"
        ]
      },
      "operations.UpdateOrderItemsReady": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Order identifier whose item ready flags are being updated",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2"
          },
          "changes": {
            "description": "Batch of ready-flag changes applied to the order in a single atomic write.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.OrderItemReadyChange"
            }
          }
        },
        "required": [
          "orderId",
          "changes"
        ]
      },
      "operations.OrderItem": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Order identifier to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2"
          },
          "state": {
            "type": "string",
            "description": "New state for the order",
            "enum": [
              "PENDING",
              "IN_PROCESS",
              "COMPLETED",
              "CANCELLED"
            ],
            "example": "IN_PROCESS"
          },
          "priority": {
            "type": "number",
            "description": "Display priority (lower = shown first)",
            "example": 10
          },
          "type": {
            "type": "string",
            "description": "Fulfillment channel",
            "enum": [
              "TAKE_AWAY",
              "DINE_IN",
              "DELIVERY"
            ],
            "example": "DELIVERY"
          },
          "customer": {
            "type": "object",
            "description": "Customer details attached to the order",
            "example": {
              "name": "Maria Gomez",
              "email": "maria@example.com",
              "phone": {
                "prefix": 34,
                "number": 600123456
              },
              "note": "Extra spicy please"
            }
          },
          "delivery": {
            "type": "object",
            "description": "Delivery details (required when type is DELIVERY)",
            "example": {
              "provider": "DEFAULT",
              "coordinates": [
                -3.7038,
                40.4168
              ],
              "address": "Calle Mayor 10",
              "zipCode": "28013",
              "city": "Madrid",
              "country": "ES"
            }
          },
          "items": {
            "description": "Updated line items for the order",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.OrderItem"
            }
          }
        },
        "required": [
          "id",
          "priority",
          "type",
          "items"
        ]
      },
      "operations.FetchOrdersBetweenDates": {
        "type": "object",
        "properties": {}
      },
      "operations.fetchOrderByIdV2": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateOrderDeliveryId": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateOrderDeliveryStatus": {
        "type": "object",
        "properties": {}
      },
      "operations.SetStationCompleted": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Order identifier to stamp",
            "example": "64f1b8a2c3d4e5f6a7b8c9f2"
          },
          "stationId": {
            "type": "string",
            "description": "Station recording the completion. Sent by the client because a KDS screen can be re-pointed at another station locally; an unknown or absent value falls back to the station configured on the calling device.",
            "example": "PREPARATION"
          },
          "completed": {
            "type": "boolean",
            "description": "true stamps the completion, false clears it (undo). Defaults to true.",
            "example": true
          }
        },
        "required": [
          "orderId"
        ]
      },
      "operations.CreateDeliveryOrderContactDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          }
        }
      },
      "operations.CreateDeliveryOrderCoordinatesDto": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          }
        },
        "required": [
          "latitude",
          "longitude"
        ]
      },
      "operations.CreateDeliveryOrderAddressDto": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "example": "ES"
          },
          "coordinates": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderCoordinatesDto"
          },
          "comment": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "door": {
            "type": "string"
          },
          "floor": {
            "type": "string"
          },
          "formattedAddress": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "zipCode": {
            "type": "string"
          }
        },
        "required": [
          "address",
          "city",
          "country",
          "coordinates"
        ]
      },
      "operations.CreateDeliveryOrderStopDto": {
        "type": "object",
        "properties": {
          "note": {
            "type": "string"
          },
          "contact": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderContactDto"
          },
          "address": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderAddressDto"
          }
        },
        "required": [
          "address"
        ]
      },
      "operations.CreateDeliveryOrderOfferDto": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "operations.CreateDeliveryOrderItemDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "quantity": {
            "type": "number"
          },
          "size": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "price",
          "quantity"
        ]
      },
      "operations.CreateDeliveryOrderMetadataDto": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string"
          },
          "orderReference": {
            "type": "string"
          },
          "priority": {
            "type": "string"
          }
        }
      },
      "operations.CreateDeliveryOrderSecurityDto": {
        "type": "object",
        "properties": {
          "requestPicture": {
            "type": "boolean",
            "default": true
          },
          "requestQR": {
            "type": "boolean",
            "default": true
          },
          "code": {
            "type": "string"
          }
        }
      },
      "operations.CreateDeliveryOrderScheduleDto": {
        "type": "object",
        "properties": {
          "deliveryAt": {
            "format": "date-time",
            "type": "string",
            "description": "Target delivery date and time (ISO 8601)"
          }
        },
        "required": [
          "deliveryAt"
        ]
      },
      "operations.CreateDeliveryOrderDto": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location identifier (Locations._id) where the order is picked up"
          },
          "provider": {
            "type": "string",
            "description": "Delivery platform/provider (e.g. GLOVO, UBER)"
          },
          "pickUp": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderStopDto"
          },
          "delivery": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderStopDto"
          },
          "offer": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderOfferDto"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.CreateDeliveryOrderItemDto"
            }
          },
          "metadata": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderMetadataDto"
          },
          "security": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderSecurityDto"
          },
          "schedule": {
            "$ref": "#/components/schemas/operations.CreateDeliveryOrderScheduleDto"
          }
        },
        "required": [
          "locationId",
          "pickUp",
          "delivery",
          "offer",
          "items"
        ]
      },
      "operations.UpdateSupportRequestStatusDto": {
        "type": "object",
        "properties": {}
      },
      "operations.ReassignCourierDto": {
        "type": "object",
        "properties": {}
      },
      "operations.CancelDeliveryOrderDto": {
        "type": "object",
        "properties": {}
      },
      "operations.InviteCourier": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateCourierLocationsDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateCourierConfigurationDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdatePerformanceThresholdDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpsertStationsFlow": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "description": "How tickets move through the stations. PARALLEL: every station sees the ticket at once, each preps its own items and EXPEDITION closes. SEQUENTIAL: the whole ticket travels station by station in the configured order (stations with no matching items are skipped) and ends at EXPEDITION.",
            "enum": [
              "PARALLEL",
              "SEQUENTIAL"
            ],
            "example": "SEQUENTIAL"
          },
          "enabled": {
            "type": "boolean",
            "description": "Disabled flows are kept but ignored: order routing behaves exactly as if no flow existed.",
            "example": true
          },
          "stations": {
            "description": "Ordered pipeline of stations. The last entry must be EXPEDITION. kdsFilter null or with empty arrays = station matches every item. release.requires lists stations that must have completed the ticket before this one sees it; every entry must appear EARLIER in the pipeline, and entries naming a station absent from the pipeline are stripped on save. Absent/empty release = the ticket appears immediately.",
            "example": [
              {
                "stationId": "GRILL",
                "kdsFilter": {
                  "itemsIds": [
                    "64f1..."
                  ],
                  "mealsIds": [],
                  "modifiersIds": []
                },
                "release": null
              },
              {
                "stationId": "EXPEDITION",
                "kdsFilter": null,
                "release": {
                  "requires": [
                    "GRILL"
                  ]
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "mode",
          "enabled",
          "stations"
        ]
      },
      "operations.CreateInvoice": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Customer legal or display name",
            "example": "Maria Gomez"
          },
          "taxId": {
            "type": "string",
            "description": "Customer tax identifier (NIF/CIF/VAT)",
            "example": "X1234567L"
          },
          "address": {
            "type": "string",
            "description": "Customer billing address",
            "example": "Calle Mayor 10, 28013 Madrid"
          },
          "receiptId": {
            "type": "string",
            "description": "Receipt id the invoice is generated from",
            "example": "RCPT-2026-0001"
          },
          "date": {
            "format": "date-time",
            "type": "string",
            "description": "Date the invoice was issued (ISO 8601)",
            "example": "2026-04-23T12:00:00.000Z"
          },
          "recursive": {
            "type": "boolean",
            "description": "Whether to save the customer data for future recurring invoices",
            "example": false
          }
        },
        "required": [
          "name",
          "taxId",
          "address",
          "receiptId",
          "date"
        ]
      },
      "operations.CreateInvoiceV2": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "description": "Transaction id the invoice is generated from",
            "example": "64f1b8a2c3d4e5f6a7b8c9a2"
          },
          "name": {
            "type": "string",
            "description": "Customer legal or display name",
            "example": "Maria Gomez"
          },
          "taxId": {
            "type": "string",
            "description": "Customer tax identifier (NIF/CIF/VAT)",
            "example": "X1234567L"
          },
          "address": {
            "type": "string",
            "description": "Customer billing address",
            "example": "Calle Mayor 10, 28013 Madrid"
          },
          "email": {
            "type": "string",
            "description": "Customer email to deliver the invoice to",
            "example": "maria@example.com"
          },
          "phone": {
            "type": "object",
            "description": "Customer phone number (split into prefix + local number)",
            "example": {
              "prefix": "+34",
              "number": "600123456"
            }
          }
        },
        "required": [
          "transactionId",
          "name",
          "taxId",
          "address",
          "email",
          "phone"
        ]
      },
      "operations.ExportInvoicesByEmail": {
        "type": "object",
        "properties": {
          "invoiceIdentifiers": {
            "description": "Invoice identifiers to include in the export",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9a3",
              "64f1b8a2c3d4e5f6a7b8c9a4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "email": {
            "type": "string",
            "description": "Email address that will receive the export",
            "example": "accountant@tacosplatomico.com"
          },
          "locale": {
            "type": "string",
            "description": "Locale for the email copy (es / en)",
            "example": "es"
          }
        },
        "required": [
          "invoiceIdentifiers",
          "email",
          "locale"
        ]
      },
      "operations.ObjectId": {
        "type": "object",
        "properties": {}
      },
      "operations.Customer": {
        "type": "object",
        "properties": {
          "id": {
            "description": "Customer id",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.ObjectId"
              }
            ]
          },
          "taxId": {
            "type": "string",
            "description": "Customer taxId"
          },
          "email": {
            "type": "string",
            "description": "Customer email"
          },
          "phone": {
            "type": "object",
            "description": "Customer phone"
          },
          "name": {
            "type": "string",
            "description": "Customer name"
          },
          "lastname": {
            "type": "string",
            "description": "Customer lastname"
          },
          "birthdate": {
            "format": "date-time",
            "type": "string",
            "description": "Customer birth date"
          },
          "address": {
            "type": "string",
            "description": "Customer address"
          },
          "loyaltyCustomerId": {
            "type": "string",
            "description": "Customer id in the external loyalty provider"
          }
        },
        "required": [
          "id",
          "taxId",
          "email",
          "phone",
          "name",
          "lastname",
          "birthdate",
          "address"
        ]
      },
      "operations.FetchCustomerByEmailPayload": {
        "type": "object",
        "properties": {}
      },
      "operations.VerifyPhone": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateDevice": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Type of device being registered. CASH_MACHINE is a LAN cash recycler driven by its linked till (trace.provider selects the adapter, net carries host/port).",
            "example": "POS"
          },
          "name": {
            "type": "string",
            "description": "Human friendly device name",
            "example": "Front counter POS"
          },
          "description": {
            "type": "string",
            "description": "Optional description for the device",
            "example": "Primary iPad at the front counter"
          },
          "version": {
            "type": "number",
            "description": "Device contract version. v2 devices use the new transport-aware dispatch (OPEN_CASH_DRAWER, USB / LAN_ANDROID transports). Defaults to 2 on the v2 endpoint and 1 on the legacy endpoint.",
            "example": 2
          },
          "trace": {
            "type": "object",
            "description": "Routing/identity metadata for the device",
            "example": {
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d0",
              "model": "IPAD",
              "serial": "F2LW4XXXXXXX",
              "stationId": "STATION_KITCHEN"
            }
          },
          "net": {
            "type": "object",
            "description": "Network configuration for devices reachable over the LAN",
            "example": {
              "protocol": "TCP",
              "port": 9100,
              "host": "192.168.1.50"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Optional printer metadata. For USB protocol, vendor/product identifiers are required so the client can match the bound USB device.",
            "example": {
              "printer": {
                "vendor": "epson",
                "widthDots": 576,
                "usb": {
                  "vendorIdentifier": 1208,
                  "productIdentifier": 514
                }
              }
            }
          }
        },
        "required": [
          "type",
          "trace"
        ]
      },
      "operations.UpdateDevice": {
        "type": "object",
        "properties": {
          "deviceId": {
            "type": "string",
            "description": "Device identifier to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "string",
            "description": "New display name for the device",
            "example": "Front counter POS"
          },
          "description": {
            "type": "string",
            "description": "Updated description for the device",
            "example": "Primary iPad at the front counter"
          },
          "status": {
            "type": "string",
            "description": "Lifecycle status for the device",
            "example": "ACTIVE"
          },
          "version": {
            "type": "number",
            "description": "Device contract version. v2 devices use the new transport-aware dispatch (OPEN_CASH_DRAWER, USB / LAN_ANDROID transports).",
            "example": 2
          },
          "trace": {
            "type": "object",
            "description": "Partial routing/identity metadata overrides. For PRINTER devices, printRouting sets per-pickup-type print routing (fail-open when absent).",
            "example": {
              "stationId": "STATION_KITCHEN",
              "printRouting": {
                "automatic": [
                  "DINE_IN",
                  "TAKE_AWAY"
                ],
                "manual": [
                  "DELIVERY"
                ]
              }
            }
          },
          "net": {
            "type": "object",
            "description": "Partial network configuration overrides",
            "example": {
              "host": "192.168.1.51"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Partial printer metadata overrides",
            "example": {
              "printer": {
                "vendor": "epson",
                "widthDots": 576
              }
            }
          },
          "knownAs": {
            "type": "object",
            "description": "External provider identifiers linked to the device",
            "example": [
              {
                "provider": "square",
                "id": "sq_dev_abc"
              }
            ]
          }
        },
        "required": [
          "deviceId"
        ]
      },
      "operations.ExecAction": {
        "type": "object",
        "properties": {
          "command": {
            "type": "string",
            "description": "Action to execute remotely on the target device(s). UPDATE_APP makes the app pull the newest OTA bundle, and when there is none it falls through to checking for a newer APK.",
            "enum": [
              "LOGOUT",
              "RELOAD",
              "UPDATE_APP"
            ],
            "example": "RELOAD"
          },
          "locationsIds": {
            "description": "Locations whose devices should receive the command",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "deviceId": {
            "type": "string",
            "description": "Specific device to target (overrides locationsIds)",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0"
          }
        },
        "required": [
          "command"
        ]
      },
      "operations.AttachedUsbPeripheral": {
        "type": "object",
        "properties": {
          "vendorIdentifier": {
            "type": "number",
            "description": "USB vendor identifier",
            "example": 1989
          },
          "productIdentifier": {
            "type": "number",
            "description": "USB product identifier",
            "example": 1280
          }
        },
        "required": [
          "vendorIdentifier",
          "productIdentifier"
        ]
      },
      "operations.AttachedLanPeripheral": {
        "type": "object",
        "properties": {
          "host": {
            "type": "string",
            "description": "LAN host (IP)",
            "example": "192.168.1.50"
          },
          "port": {
            "type": "number",
            "description": "LAN port",
            "example": 9100
          }
        },
        "required": [
          "host",
          "port"
        ]
      },
      "operations.PostHeartbeat": {
        "type": "object",
        "properties": {
          "appVersion": {
            "type": "string",
            "description": "App (Platomico) version running on the device",
            "example": "2.14.0"
          },
          "nativeBuildVersion": {
            "type": "string",
            "description": "Native build version of the installed binary (Android versionCode / iOS build number). This is what an APK self-update compares against a published release; appVersion is display only.",
            "example": "312"
          },
          "updateId": {
            "type": "string",
            "description": "Id of the OTA bundle running on top of the binary, or 'embedded' when the device is still on the bundle shipped inside the APK.",
            "example": "a1b2c3d4-0000-4444-8888-abcdefabcdef"
          },
          "osVersion": {
            "type": "string",
            "description": "Operating system version of the device",
            "example": "iPadOS 17.4"
          },
          "platform": {
            "type": "string",
            "description": "Platform identifier for the device",
            "example": "iOS"
          },
          "batteryLevel": {
            "type": "number",
            "description": "Battery charge as a 0..1 fraction. Omit (or send -1, as expo-battery does) when the hardware reports no battery — the server drops out-of-range values rather than storing a misleading 0%.",
            "example": 0.62
          },
          "batteryState": {
            "type": "string",
            "description": "Battery state at the time of the beat. Mirrors expo-battery BatteryState by name.",
            "enum": [
              "UNKNOWN",
              "UNPLUGGED",
              "CHARGING",
              "FULL"
            ],
            "example": "UNPLUGGED"
          },
          "attachedUsb": {
            "description": "USB peripherals (printers / cash drawers) currently attached to this device. Used by the server to bump connectivity on the matching peripheral records.",
            "example": [
              {
                "vendorIdentifier": 1989,
                "productIdentifier": 1280
              }
            ],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.AttachedUsbPeripheral"
            }
          },
          "attachedLan": {
            "description": "LAN peripherals (host:port pairs) the till has just confirmed reachable via TCP probe. Used to bump connectivity on the matching LAN_ANDROID peripheral records.",
            "example": [
              {
                "host": "192.168.1.50",
                "port": 9100
              }
            ],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.AttachedLanPeripheral"
            }
          }
        }
      },
      "operations.PeripheralOfflineUsb": {
        "type": "object",
        "properties": {
          "vendorIdentifier": {
            "type": "number",
            "description": "USB vendor identifier of the peripheral that was just detached",
            "example": 1989
          },
          "productIdentifier": {
            "type": "number",
            "description": "USB product identifier of the peripheral that was just detached",
            "example": 1280
          }
        },
        "required": [
          "vendorIdentifier",
          "productIdentifier"
        ]
      },
      "operations.PeripheralOfflineLan": {
        "type": "object",
        "properties": {
          "host": {
            "type": "string",
            "description": "LAN host of the peripheral that was just detached",
            "example": "192.168.1.50"
          },
          "port": {
            "type": "number",
            "description": "LAN port of the peripheral that was just detached",
            "example": 9100
          }
        },
        "required": [
          "host",
          "port"
        ]
      },
      "operations.PeripheralOffline": {
        "type": "object",
        "properties": {
          "usb": {
            "description": "USB peripheral identifiers (set when a USB device was detached)",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.PeripheralOfflineUsb"
              }
            ]
          },
          "lan": {
            "description": "LAN peripheral identifiers (set when a LAN device went unreachable)",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.PeripheralOfflineLan"
              }
            ]
          }
        }
      },
      "operations.UpdateDevicePreferences": {
        "type": "object",
        "properties": {
          "deviceId": {
            "type": "string",
            "description": "Device whose preferences are being written. Required for dashboard callers. IGNORED when the caller is the device itself — a device may only write its own preferences, so the target is taken from its session.",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0"
          },
          "preferences": {
            "type": "object",
            "description": "Partial preferences patch. Only keys the device type understands are kept; unrecognized keys and invalid values are dropped rather than stored. Keys are written individually, so omitting one leaves the stored value untouched.",
            "example": {
              "layoutId": "twoRail",
              "textSize": "LARGE",
              "soundEnabled": false,
              "items": {
                "showMeals": false
              }
            }
          }
        },
        "required": [
          "preferences"
        ]
      },
      "operations.Font": {
        "type": "object",
        "properties": {}
      },
      "operations.Theme": {
        "type": "object",
        "properties": {}
      },
      "operations.Terminal": {
        "type": "object",
        "properties": {}
      },
      "operations.Radius": {
        "type": "object",
        "properties": {}
      },
      "operations.UI": {
        "type": "object",
        "properties": {}
      },
      "operations.Settings": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Settings document name",
            "example": "Front counter layout"
          },
          "type": {
            "type": "string",
            "description": "Settings type (e.g. POS., KDS., KIOSK.)",
            "example": "POS."
          },
          "logo": {
            "type": "string",
            "description": "Logo URL used in the device UI",
            "example": "https://cdn.platomico.com/logo.png"
          },
          "font": {
            "description": "Font preferences",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Font"
              }
            ]
          },
          "customFonts": {
            "description": "Company-uploaded font files available to devices in addition to the bundled families. `family` is the key referenced by `font.primary/secondary/tertiary`; `url` points at the uploaded ttf/otf on S3.",
            "example": [
              {
                "family": "IMPACT",
                "label": "Impact",
                "url": "https://cdn.platomico.com/fonts/impact.ttf"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "theme": {
            "description": "Theme (colors)",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Theme"
              }
            ]
          },
          "terminal": {
            "description": "Terminal / payment settings",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Terminal"
              }
            ]
          },
          "radius": {
            "description": "Border radius presets",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Radius"
              }
            ]
          },
          "ui": {
            "description": "Layout + grid definition",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.UI"
              }
            ]
          },
          "settings": {
            "type": "object",
            "description": "Extended configuration (accepted tenders, channels, features, links)",
            "example": {
              "accept": [
                "CARD",
                "CASH"
              ],
              "options": [
                "TAKE_AWAY",
                "DINE_IN"
              ],
              "features": [
                "loyalty"
              ],
              "links": {
                "support": "https://support.platomico.com"
              }
            }
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata",
            "example": {
              "companyId": "64f1b8a2c3d4e5f6a7b8c9c0",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ]
            }
          },
          "knownAs": {
            "description": "External provider identifiers linked to this settings doc",
            "example": [
              {
                "provider": "square",
                "id": "sq_settings_abc"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "kdsFilter": {
            "type": "object",
            "description": "KDS catalog filter: limits which items / meals / modifiers a KDS using this profile sees. Empty arrays = no constraint on that kind. Object absent = no filter.",
            "example": {
              "itemsIds": [
                "64f1b8a2c3d4e5f6a7b8c9aa"
              ],
              "mealsIds": [],
              "modifiersIds": []
            }
          }
        },
        "required": [
          "name",
          "type",
          "theme",
          "terminal",
          "radius",
          "ui",
          "trace"
        ]
      },
      "operations.BulkGridUpdate": {
        "type": "object",
        "properties": {
          "locationsIds": {
            "description": "Locations whose device settings should receive the grid update",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "grid": {
            "description": "Grid cells to apply (items, meals, groups, sections)",
            "example": [
              {
                "coords": {
                  "x": [
                    0,
                    1
                  ],
                  "y": [
                    0,
                    1
                  ]
                },
                "type": "ITEM",
                "id": "64f1b8a2c3d4e5f6a7b8c9a5"
              },
              {
                "coords": {
                  "x": [
                    1,
                    3
                  ],
                  "y": [
                    0,
                    1
                  ]
                },
                "type": "SECTION",
                "name": "Drinks"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settingsIds": {
            "description": "Specific settings documents to target (otherwise all matching locations)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9b0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationsIds",
          "grid"
        ]
      },
      "operations.CreateSchedule": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Schedule name",
            "example": "Lunch menu"
          },
          "locationId": {
            "type": "string",
            "description": "Location this schedule applies to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "days": {
            "type": "object",
            "description": "Weekly time windows keyed by weekday (mon-sun)",
            "example": {
              "mon": [
                {
                  "from": "12:00",
                  "to": "16:00"
                }
              ],
              "tue": [
                {
                  "from": "12:00",
                  "to": "16:00"
                }
              ]
            }
          },
          "type": {
            "type": "string",
            "description": "Schedule type (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU"
          },
          "destinationsIds": {
            "description": "Entities this schedule applies to (e.g. menu ids)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9a5"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sourcesIds": {
            "description": "Source entities that trigger this schedule",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9a6"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "locationId",
          "days",
          "type",
          "destinationsIds",
          "sourcesIds"
        ]
      },
      "operations.UpdateSchedule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Schedule id to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9a7"
          },
          "name": {
            "type": "string",
            "description": "Schedule name",
            "example": "Lunch menu"
          },
          "locationId": {
            "type": "string",
            "description": "Location this schedule applies to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "days": {
            "type": "object",
            "description": "Weekly time windows keyed by weekday (mon-sun)",
            "example": {
              "mon": [
                {
                  "from": "12:00",
                  "to": "16:00"
                }
              ]
            }
          },
          "type": {
            "type": "string",
            "description": "Schedule type (MENU, OFFER, DEVICE, etc.)",
            "example": "MENU"
          },
          "destinationsIds": {
            "description": "Entities this schedule applies to (e.g. menu ids)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9a5"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sourcesIds": {
            "description": "Source entities that trigger this schedule",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9a6"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "operations.CreateTaskDone": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier generated client-side (idempotency)",
            "example": "64f1b8a2c3d4e5f6a7b8c9f5"
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata pointing at the task template",
            "example": {
              "taskId": "64f1b8a2c3d4e5f6a7b8c9e4"
            }
          },
          "response": {
            "type": "object",
            "description": "Response body: member, input values and timestamp",
            "example": {
              "member": {
                "id": "64f1b8a2c3d4e5f6a7b8c9e2",
                "name": "Maria Gomez"
              },
              "inputs": [
                {
                  "type": "IMAGE",
                  "name": "Before-photo",
                  "required": true,
                  "value": "https://cdn.platomico.com/tasks/done/before.jpg"
                }
              ],
              "createdAt": "2026-04-23T12:00:00.000Z"
            }
          },
          "cooldown": {
            "type": "number",
            "description": "Cooldown (seconds) before the task can be completed again",
            "example": 3600
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "Completion timestamp",
            "example": "2026-04-23T12:00:00.000Z"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "Last update timestamp",
            "example": "2026-04-23T12:00:00.000Z"
          }
        },
        "required": [
          "id",
          "trace",
          "response",
          "cooldown",
          "createdAt",
          "updatedAt"
        ]
      },
      "operations.TraceDto": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location the task runs at",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "locationId"
        ]
      },
      "operations.InputDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Input name shown to the member",
            "example": "Before-photo"
          },
          "type": {
            "type": "string",
            "description": "Input type",
            "enum": [
              "STRING",
              "TEXT_AREA",
              "CHECK",
              "PHOTO",
              "NUMBER"
            ],
            "example": "IMAGE"
          },
          "description": {
            "type": "string",
            "description": "Help text for the input",
            "example": "Take a picture of the floor before cleaning"
          },
          "extension": {
            "type": "string",
            "description": "File extension for file-typed inputs",
            "example": "jpg"
          },
          "required": {
            "type": "boolean",
            "description": "Whether the member must provide this input to complete the task",
            "example": true
          }
        },
        "required": [
          "name",
          "type",
          "required"
        ]
      },
      "operations.CreateTask": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Task title",
            "example": "Mop the kitchen floor"
          },
          "description": {
            "type": "string",
            "description": "Task description",
            "example": "Mop the kitchen floor at the end of every shift."
          },
          "cooldown": {
            "type": "number",
            "description": "Cooldown (in seconds) before the task can be marked done again",
            "example": 3600
          },
          "image": {
            "type": "string",
            "description": "Illustrative image URL",
            "example": "https://cdn.platomico.com/tasks/mop.png"
          },
          "trace": {
            "description": "Routing metadata (location the task runs at)",
            "example": {
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d0"
            },
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.TraceDto"
              }
            ]
          },
          "inputs": {
            "description": "Inputs the member has to fill when marking the task done",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.InputDto"
            }
          },
          "events": {
            "description": "Optional workflow events triggered after completion",
            "example": [
              {
                "type": "NOTIFY",
                "channel": "email",
                "target": "manager"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "cooldown",
          "trace"
        ]
      },
      "operations.Trace": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location the task runs at",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "locationId"
        ]
      },
      "operations.UpdateTask": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Task identifier",
            "example": "64f1b8a2c3d4e5f6a7b8c9e4"
          },
          "trace": {
            "description": "Routing metadata",
            "example": {
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d0"
            },
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Trace"
              }
            ]
          },
          "title": {
            "type": "string",
            "description": "Updated title",
            "example": "Mop the kitchen floor"
          },
          "description": {
            "type": "string",
            "description": "Updated description",
            "example": "Mop the kitchen floor at end of every shift."
          },
          "cooldown": {
            "type": "boolean",
            "description": "Updated cooldown in seconds",
            "example": 3600
          },
          "image": {
            "type": "string",
            "description": "Updated image URL",
            "example": "https://cdn.platomico.com/tasks/mop.png"
          },
          "visibl": {
            "type": "boolean",
            "description": "Toggle task visibility",
            "example": true
          },
          "active": {
            "type": "boolean",
            "description": "Toggle task active state",
            "example": true
          },
          "inputs": {
            "description": "Updated inputs",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.InputDto"
            }
          },
          "events": {
            "description": "Updated events",
            "example": [
              {
                "type": "NOTIFY",
                "channel": "email",
                "target": "manager"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "trace"
        ]
      },
      "operations.TaskId": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Task identifier",
            "example": "64f1b8a2c3d4e5f6a7b8c9e4"
          }
        },
        "required": [
          "id"
        ]
      },
      "operations.Member": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Member first name",
            "example": "Maria"
          },
          "lastName": {
            "type": "string",
            "description": "Member last name",
            "example": "Gomez"
          },
          "image": {
            "type": "string",
            "description": "Avatar image URL",
            "example": "https://cdn.platomico.com/members/maria.jpg"
          },
          "role": {
            "type": "string",
            "description": "Member role (Manager, Cashier, Chef...)",
            "example": "Manager"
          },
          "email": {
            "type": "string",
            "description": "Member email address",
            "example": "maria@tacosplatomico.com"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the member account is active",
            "example": true
          },
          "phone": {
            "type": "object",
            "description": "Member phone number (prefix + local number)",
            "example": {
              "ext": "+34",
              "number": "600123456"
            }
          },
          "code": {
            "type": "number",
            "description": "Numeric pin code the member uses to sign in on a device",
            "example": 482913
          },
          "roleId": {
            "type": "string",
            "description": "Identifier of the role assigned to the member",
            "example": "69ca70599588542b854b5503"
          },
          "contractedHours": {
            "type": "number",
            "description": "Weekly contracted hours (Mon-Sun) used for shift planning",
            "example": 37.5
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata (linked user, company, locations)",
            "example": {
              "userId": "64f1b8a2c3d4e5f6a7b8c9e2",
              "companyId": "64f1b8a2c3d4e5f6a7b8c9c0",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ]
            }
          },
          "tags": {
            "description": "Free-form tags attached to the member",
            "example": [
              "fulltime",
              "morning-shift"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "External provider identifiers linked to the member",
            "example": [
              {
                "provider": "square",
                "id": "sq_member_abc"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "lastName",
          "code",
          "trace",
          "tags",
          "knownAs"
        ]
      },
      "operations.UpdateMember": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Member id",
            "example": "64f1b8a2c3d4e5f6a7b8c9e2"
          },
          "name": {
            "type": "string",
            "description": "Updated first name",
            "example": "Maria"
          },
          "lastName": {
            "type": "string",
            "description": "Updated last name",
            "example": "Gomez"
          },
          "image": {
            "type": "string",
            "description": "Updated avatar URL",
            "example": "https://cdn.platomico.com/members/maria.jpg"
          },
          "role": {
            "type": "string",
            "description": "Updated role",
            "example": "Manager"
          },
          "email": {
            "type": "string",
            "description": "Updated email address",
            "example": "maria@tacosplatomico.com"
          },
          "active": {
            "type": "boolean",
            "description": "Updated active state",
            "example": true
          },
          "roleId": {
            "type": "string",
            "description": "Updated role identifier",
            "example": "69ca70599588542b854b5503"
          },
          "phone": {
            "type": "object",
            "description": "Updated phone number",
            "example": {
              "ext": "+34",
              "number": "600123456"
            }
          },
          "code": {
            "type": "number",
            "description": "Updated 4-digit pin (0–9999) used to sign in on a device",
            "example": 256
          },
          "contractedHours": {
            "type": "number",
            "description": "Updated weekly contracted hours (Mon-Sun)",
            "example": 37.5
          },
          "locationsIds": {
            "description": "Updated accessible locations; [\"*\"] grants all locations",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id"
        ]
      },
      "operations.BulkUpdateRole": {
        "type": "object",
        "properties": {
          "memberIds": {
            "description": "Ids of the members whose role should be updated",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9e2",
              "64f1b8a2c3d4e5f6a7b8c9e3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "roleId": {
            "type": "string",
            "description": "Role identifier to assign to every selected member",
            "example": "69ca70599588542b854b5503"
          },
          "role": {
            "type": "string",
            "description": "Role display name to assign (kept in sync with roleId)",
            "example": "MANAGER"
          }
        },
        "required": [
          "memberIds",
          "roleId"
        ]
      },
      "operations.ClockByCodeDto": {
        "type": "object",
        "properties": {}
      },
      "operations.ClockInDto": {
        "type": "object",
        "properties": {}
      },
      "operations.ClockOutDto": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateShiftTemplateDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateShiftTemplateDto": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateShiftAbsenceDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateShiftAbsenceDto": {
        "type": "object",
        "properties": {}
      },
      "operations.DecideRequestDto": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateShiftDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateShiftDto": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateShiftOverrideDto": {
        "type": "object",
        "properties": {}
      },
      "operations.UpdateShiftOverrideDto": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateAbsenceRequestDto": {
        "type": "object",
        "properties": {}
      },
      "operations.OrderPipeline": {
        "type": "object",
        "properties": {}
      },
      "operations.StampsSettings": {
        "type": "object",
        "properties": {}
      },
      "operations.CreateProgram": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Program display name",
            "example": "Coffee lovers"
          },
          "type": {
            "type": "string",
            "description": "Program mechanic (stamps, points, tiered, etc.)",
            "example": "STAMPS"
          },
          "settings": {
            "description": "Program mechanic settings",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.StampsSettings"
              }
            ]
          },
          "tags": {
            "description": "Free-form tags attached to the program",
            "example": [
              "coffee",
              "welcome"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ]
            }
          }
        },
        "required": [
          "name",
          "type",
          "settings",
          "trace"
        ]
      },
      "operations.createReward": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Routing metadata linking the reward to a program and target entity",
            "example": {
              "itemId": "64f1b8a2c3d4e5f6a7b8c9a5",
              "discountId": "",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "programId": "64f1b8a2c3d4e5f6a7b8c9b5"
            }
          },
          "override": {
            "type": "object",
            "description": "Content overrides for the reward (name, description, image, modifiers)",
            "example": {
              "name": "Free coffee",
              "description": "Your 10th coffee is on us"
            }
          },
          "tags": {
            "description": "Free-form tags attached to the reward",
            "example": [
              "welcome"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "trace"
        ]
      },
      "operations.CreateBenefit": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Link between the benefit and the target item / meal / discount",
            "example": {
              "type": "ITEM",
              "itemId": "64f1b8a2c3d4e5f6a7b8c9a5",
              "discountId": "",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "programId": "64f1b8a2c3d4e5f6a7b8c9b5"
            }
          },
          "price": {
            "type": "object",
            "description": "Price override when redeeming the benefit",
            "example": {
              "amount": 0,
              "currency": "EUR"
            }
          },
          "override": {
            "type": "object",
            "description": "Per-benefit content overrides (name, description, image, modifiers)",
            "example": {
              "name": "Free coffee",
              "description": "Your 10th coffee is on us"
            }
          },
          "settings": {
            "type": "object",
            "description": "Redemption settings (auto-apply, quotas, time-of-day, scope)",
            "example": {
              "autoapply": false,
              "uses": {
                "max": 1,
                "per": "DAY"
              },
              "time": {
                "from": "08:00",
                "to": "22:00"
              },
              "scope": [
                "ITEM"
              ]
            }
          },
          "tags": {
            "description": "Free-form tags attached to the benefit",
            "example": [
              "welcome",
              "coffee"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "trace",
          "settings"
        ]
      },
      "operations.CreateTemplate": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Routing metadata linking the template to a program and color",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "programId": "64f1b8a2c3d4e5f6a7b8c9b5",
              "colorId": "64f1b8a2c3d4e5f6a7b8c9b7"
            }
          },
          "name": {
            "type": "string",
            "description": "Template display name",
            "example": "Coffee lovers - default template"
          },
          "google": {
            "type": "object",
            "description": "Google Wallet visual + field configuration",
            "example": {
              "style": {
                "logo": "https://cdn.platomico.com/loyalty/logo.png",
                "banner": [
                  "https://cdn.platomico.com/loyalty/banner.png"
                ],
                "backgroundColor": "#FF6600",
                "textColor": "#FFFFFF"
              },
              "fields": [
                {
                  "key": "member_id",
                  "label": "Member ID"
                }
              ]
            }
          },
          "apple": {
            "type": "object",
            "description": "Apple Wallet visual + field configuration",
            "example": {
              "style": {
                "logo": "https://cdn.platomico.com/loyalty/logo.png",
                "banner": [
                  "https://cdn.platomico.com/loyalty/banner.png"
                ],
                "backgroundColor": "#FF6600",
                "textColor": "#FFFFFF"
              },
              "fields": [
                {
                  "key": "member_id",
                  "label": "Member ID"
                }
              ]
            }
          },
          "tags": {
            "description": "Free-form tags attached to the template",
            "example": [
              "default",
              "coffee"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "trace",
          "name",
          "google",
          "apple",
          "tags"
        ]
      },
      "operations.CreateColor": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Routing metadata linking the color palette to companies/locations",
            "example": {
              "colorId": "64f1b8a2c3d4e5f6a7b8c9b7",
              "companiesIds": [
                "64f1b8a2c3d4e5f6a7b8c9c0"
              ],
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ]
            }
          },
          "name": {
            "type": "string",
            "description": "Display name of the color",
            "example": "Platomico orange"
          },
          "hex": {
            "type": "string",
            "description": "Hex color code",
            "example": "#FF6600"
          },
          "tags": {
            "description": "Free-form tags attached to the color",
            "example": [
              "brand",
              "primary"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "trace",
          "name",
          "hex"
        ]
      },
      "operations.Maintenance": {
        "type": "object",
        "properties": {
          "serviceName": {
            "type": "string",
            "description": "Target service to run maintenance on",
            "example": "operations-service"
          },
          "serviceModule": {
            "type": "string",
            "description": "Optional submodule to scope the maintenance to",
            "example": "orders"
          },
          "actions": {
            "description": "Maintenance actions to execute in order",
            "example": [
              "FLUSH_CACHE",
              "REBUILD_INDEX"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "options": {
            "type": "object",
            "description": "Scheduling window and notification options",
            "example": {
              "startTime": "2026-04-23T00:00:00.000Z",
              "endTime": "2026-04-23T02:00:00.000Z",
              "notifyAdmins": true
            }
          },
          "reason": {
            "type": "string",
            "description": "Reason for the maintenance (logged with the audit record)",
            "example": "Quarterly index rebuild"
          }
        },
        "required": [
          "serviceName",
          "actions",
          "options"
        ]
      },
      "operations.ServiceStatus": {
        "type": "object",
        "properties": {
          "serviceName": {
            "type": "string",
            "description": "Target service whose status is being updated or queried",
            "example": "operations-service"
          }
        },
        "required": [
          "serviceName"
        ]
      },
      "operations.AuditImageStateDTO": {
        "type": "object",
        "properties": {
          "tag": {
            "type": "string",
            "description": "How the image is being provided",
            "enum": [
              "none",
              "base64",
              "URL"
            ],
            "example": "base64"
          },
          "base64": {
            "type": "string",
            "description": "Base64-encoded image payload (when tag is \"base64\")",
            "example": "iVBORw0KGgoAAAANSUhEUgAAAAUA..."
          },
          "extension": {
            "type": "string",
            "description": "File extension of the image",
            "example": "png"
          },
          "contentType": {
            "type": "string",
            "description": "MIME content type of the image",
            "example": "image/png"
          },
          "URL": {
            "type": "string",
            "description": "Absolute image URL (when tag is \"URL\")",
            "example": "https://cdn.platomico.com/audits/abc.png"
          }
        },
        "required": [
          "tag",
          "base64",
          "extension",
          "contentType"
        ]
      },
      "operations.ItemDTO": {
        "type": "object",
        "properties": {
          "questionId": {
            "type": "string",
            "description": "Question identifier within the audit type",
            "example": "64f1b8a2c3d4e5f6a7b8c9e1"
          },
          "question": {
            "type": "string",
            "description": "Question text answered by the member",
            "example": "Is the kitchen floor clean?"
          },
          "choice": {
            "type": "string",
            "description": "Selected choice identifier or label",
            "example": "YES"
          },
          "answer": {
            "type": "object",
            "description": "Free-form answer (string or structured object)",
            "example": "Some surfaces still wet after cleaning"
          },
          "image": {
            "description": "Optional image attached to this response",
            "example": {
              "tag": "base64",
              "base64": "iVBORw0KGgoAAAANSUhEUgAAAAUA...",
              "extension": "png",
              "contentType": "image/png"
            },
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.AuditImageStateDTO"
              }
            ]
          }
        },
        "required": [
          "questionId",
          "question",
          "choice"
        ]
      },
      "operations.CreateAuditResponse": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Audit type identifier (e.g. cleanliness, opening checklist)",
            "example": "cleanliness"
          },
          "draft": {
            "type": "boolean",
            "description": "Save as draft instead of submitting the audit",
            "example": false
          },
          "locationId": {
            "type": "string",
            "description": "Location the audit was performed at",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationName": {
            "type": "string",
            "description": "Human-readable name of the location (denormalized)",
            "example": "Tacos Platomico - Sol"
          },
          "items": {
            "description": "Answers submitted for each question of the audit type",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.ItemDTO"
            }
          }
        },
        "required": [
          "type",
          "locationId",
          "items"
        ]
      },
      "operations.CreateEndpoint": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human readable endpoint name",
            "example": "Tacos Platomico Order Online"
          },
          "domains": {
            "description": "Ordered list of custom domains bound to the endpoint. Index 0 is the default domain — the canonical URL used wherever a single link is needed.",
            "example": [
              "order.platomico.com",
              "order.tacosplatomico.com"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "type": {
            "type": "string",
            "description": "Which frontend this endpoint backs. Absent means WEB, for compatibility with endpoints created before the field existed.",
            "enum": [
              "WEB",
              "PORTAL",
              "MEMBER",
              "LOYALTY"
            ],
            "example": "WEB"
          },
          "scopes": {
            "description": "Scope identifiers that restrict what this endpoint exposes",
            "example": [
              "ORDER",
              "QR"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locationsIds": {
            "description": "Locations this endpoint can serve",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0",
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settings": {
            "description": "Branding and integration settings for the endpoint",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Settings"
              }
            ]
          }
        },
        "required": [
          "name",
          "domains",
          "settings"
        ]
      },
      "operations.UpdateEndpoint": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human readable endpoint name",
            "example": "Tacos Platomico Order Online"
          },
          "type": {
            "type": "string",
            "description": "Which frontend this endpoint backs. Endpoints created before this field existed carry no type and are treated as WEB; setting it here makes them resolvable by type.",
            "enum": [
              "WEB",
              "PORTAL",
              "MEMBER",
              "LOYALTY"
            ],
            "example": "WEB"
          },
          "locationsIds": {
            "description": "Locations this endpoint serves. [\"*\"] means every location of the company.",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "operations.UpdateEndpointDomains": {
        "type": "object",
        "properties": {
          "domains": {
            "description": "The complete ordered list of domains bound to the endpoint. Index 0 is the DEFAULT domain — the canonical URL used wherever a single link is needed (order tracking SMS, member portal links, invoice QR). Send the whole array: it replaces the stored one, so this single call covers adding, removing, reordering and picking the default.",
            "example": [
              "order.tacosplatomico.com",
              "tacos.platomico.site"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "type": {
            "type": "string",
            "description": "Which frontend this endpoint backs. Endpoints created before this field existed carry no type and are treated as WEB; set it here to make them resolvable by type.",
            "enum": [
              "WEB",
              "PORTAL",
              "MEMBER",
              "LOYALTY"
            ],
            "example": "WEB"
          }
        },
        "required": [
          "domains"
        ]
      },
      "operations.UpdateEndpointSettings": {
        "type": "object",
        "properties": {
          "ui": {
            "type": "object",
            "description": "Element-level style overrides. Shallow-merged into the existing `ui`, so a caller that sends only `override` keeps `pageThemes` and `itemPalettes` intact.",
            "example": {
              "override": {
                "WEB:MENU.menu.item": {
                  "style": {
                    "backgroundColor": "#FFF3B0"
                  }
                }
              },
              "pageThemes": {
                "WEB:MENU": {
                  "background": "#2B2B3C"
                }
              },
              "itemPalettes": {
                "WEB:MENU.menu.item": [
                  {
                    "backgroundColor": "#EEE"
                  }
                ]
              }
            }
          },
          "logo": {
            "type": "string",
            "description": "Brand logo URL"
          },
          "icon": {
            "type": "string",
            "description": "Favicon URL"
          },
          "seo": {
            "type": "object",
            "description": "SEO metadata for the storefront. Editing it purges the 4h `endpoint-seo-*` cache."
          },
          "online": {
            "type": "object",
            "description": "Online payment provider. Editing it purges the 4h `endpoint-provider-*` cache."
          },
          "theme": {
            "description": "Brand palette",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Theme"
              }
            ]
          },
          "font": {
            "description": "Font slots",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Font"
              }
            ]
          },
          "radius": {
            "description": "Corner radii",
            "allOf": [
              {
                "$ref": "#/components/schemas/operations.Radius"
              }
            ]
          },
          "customFonts": {
            "description": "The KEPT list of company-uploaded fonts. Assigned wholesale, so omitting an entry deletes it; new files travel in `fontFiles`.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "image": {
            "type": "object",
            "description": "A new logo as base64. Uploaded to S3 and stored as `settings.logo`; the caller cannot reach the bucket itself."
          },
          "fontFiles": {
            "description": "Font files as base64. Uploaded to S3 and appended to `customFonts`, replacing any entry with the same `family`.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "uiImages": {
            "description": "Background pictures chosen in the studio. Each is uploaded to S3 and its URL written onto the named style override, so a full-size photo is never inlined into the settings document.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "operations.OnboardingProgressDto": {
        "type": "object",
        "properties": {
          "version": {
            "type": "number",
            "description": "Payload schema version",
            "example": 1
          },
          "config": {
            "type": "object",
            "description": "The onboarding answers collected so far",
            "example": {
              "business": {
                "businessName": "Café Luna"
              }
            }
          },
          "currentStep": {
            "type": "string",
            "description": "Current wizard step",
            "example": "hours"
          },
          "furthestReachedIndex": {
            "type": "number",
            "description": "Furthest step index the user has reached",
            "example": 2
          },
          "completedAt": {
            "type": "string",
            "description": "ISO completion timestamp, or null while in progress",
            "example": null,
            "nullable": true
          }
        },
        "required": [
          "version",
          "config",
          "currentStep",
          "furthestReachedIndex",
          "completedAt"
        ]
      },
      "operations.SeedOnboardingInviteOwner": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "email"
        ]
      },
      "operations.SeedOnboardingInvitePrefill": {
        "type": "object",
        "properties": {
          "businessName": {
            "type": "string"
          }
        }
      },
      "operations.SeedOnboardingInvite": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Existing os company id to onboard (deal.clientCompanyIdentifier)"
          },
          "locale": {
            "type": "string",
            "enum": [
              "es",
              "en"
            ]
          },
          "owner": {
            "$ref": "#/components/schemas/operations.SeedOnboardingInviteOwner"
          },
          "prefill": {
            "$ref": "#/components/schemas/operations.SeedOnboardingInvitePrefill"
          }
        },
        "required": [
          "companyId",
          "owner"
        ]
      },
      "operations.ChannelGroupDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "User-visible group name",
            "example": "Card terminals"
          },
          "channels": {
            "description": "Channel labels assigned to this group",
            "example": [
              "Stripe",
              "Square"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "channels"
        ]
      },
      "operations.ChannelGroupsPreferenceResponse": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "example": true
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.ChannelGroupDto"
            }
          },
          "channelOrder": {
            "example": [
              "Cash",
              "Stripe",
              "Square"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "enabled",
          "groups",
          "channelOrder"
        ]
      },
      "operations.UpdateChannelGroupsPreference": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether grouping is currently enabled",
            "example": true
          },
          "groups": {
            "description": "Custom channel groups",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/operations.ChannelGroupDto"
            }
          },
          "channelOrder": {
            "description": "Channel display order (drag-reorderable in the drawer)",
            "example": [
              "Cash",
              "Stripe",
              "Square"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "enabled",
          "groups",
          "channelOrder"
        ]
      },
      "operations.CreateIncidentDto": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "enum": [
              "orders",
              "paymentsBilling",
              "devices",
              "integrations",
              "delivery",
              "catalogProducts",
              "accountAccess",
              "other"
            ]
          },
          "description": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "email"
            ]
          }
        },
        "required": [
          "category",
          "description",
          "channel"
        ]
      },
      "operations.UpdateIncidentDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "open",
              "inProgress",
              "resolved",
              "closed"
            ]
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ]
          }
        }
      },
      "operations.CreateAppRelease": {
        "type": "object",
        "properties": {
          "applicationId": {
            "type": "string",
            "description": "Android applicationId of the binary this release upgrades",
            "example": "kitchen.platomico.com"
          },
          "channel": {
            "type": "string",
            "description": "Release channel, matching the expo-updates channel baked into the build. Defaults to \"production\" when omitted.",
            "example": "production"
          },
          "versionName": {
            "type": "string",
            "description": "Human-facing version name. Displayed, never compared.",
            "example": "1.4.2"
          },
          "versionCode": {
            "type": "number",
            "description": "Android versionCode. Devices install this release when it is strictly greater than their own native build version.",
            "example": 312
          },
          "url": {
            "type": "string",
            "description": "Direct download URL for the APK",
            "example": "https://expo.dev/artifacts/eas/abc123.apk"
          },
          "notes": {
            "type": "string",
            "description": "Release notes shown to the operator before installing",
            "example": "Faster ticket printing"
          },
          "mandatory": {
            "type": "boolean",
            "description": "Reserved for a future forced-install path",
            "example": false
          }
        },
        "required": [
          "applicationId",
          "versionName",
          "versionCode",
          "url"
        ]
      },
      "payments.OrderItem": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Id of the parent order this item belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "hash": {
            "type": "string",
            "description": "Deterministic hash of the item (id + modifiers) used for deduplication",
            "example": "f8e4c0b2a19d"
          },
          "type": {
            "type": "string",
            "description": "Whether the row refers to a catalog item or a composed meal",
            "example": "ITEM",
            "enum": [
              "ITEM",
              "MEAL"
            ]
          },
          "id": {
            "type": "string",
            "description": "Catalog item or meal id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "quantity": {
            "type": "number",
            "description": "Number of units of this item",
            "example": 2
          },
          "modifiers": {
            "description": "Selected modifiers with their quantities",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                "quantity": 1
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "price": {
            "type": "object",
            "description": "Unit price of the item",
            "example": {
              "amount": 1250,
              "currency": "EUR"
            }
          },
          "steps": {
            "description": "Nested item steps (for meals composed of groups of items)",
            "example": [],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "orderId",
          "hash",
          "type",
          "id",
          "quantity",
          "modifiers",
          "price",
          "steps"
        ]
      },
      "payments.Order": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Trace metadata (pass attached, source channel, menu sold from)",
            "example": {
              "passId": "64f1b8a2c3d4e5f6a7b8c9d0",
              "source": "POS.",
              "menuId": "64f1b8a2c3d4e5f6a7b8c9d3"
            }
          },
          "type": {
            "type": "string",
            "description": "Order fulfilment type",
            "example": "DINE_IN",
            "enum": [
              "DINE_IN",
              "TAKE_AWAY",
              "DELIVERY"
            ]
          },
          "note": {
            "type": "string",
            "description": "Free-form note for the order (e.g. for the kitchen)",
            "example": "Allergic to peanuts"
          },
          "customer": {
            "type": "object",
            "description": "Customer contact info",
            "example": {
              "name": "Jane Doe",
              "email": "customer@platomico.com",
              "phone": {
                "prefix": "+34",
                "number": "600123456"
              }
            }
          },
          "pickup": {
            "type": "object",
            "description": "Scheduled pickup time (ISO timestamp plus human-readable format)",
            "example": {
              "iso": "2026-04-23T13:30:00.000Z",
              "format": "13:30"
            }
          },
          "delivery": {
            "type": "object",
            "description": "Delivery details (only for DELIVERY orders)",
            "example": {
              "provider": "CATCHER",
              "coordinates": [
                -3.7038,
                40.4168
              ],
              "address": "Calle Mayor 10",
              "floor": "3",
              "door": "B",
              "zipCode": "28013",
              "city": "Madrid",
              "country": "ES",
              "comment": "Ring the bell twice"
            }
          },
          "payment": {
            "type": "object",
            "description": "Payment details (method, discounts, optional intent)",
            "example": {
              "method": "CARD",
              "tendered": 0,
              "discountsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "provider": "STRIPE"
            }
          },
          "items": {
            "description": "Line items in the order",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.Item"
            }
          },
          "utils": {
            "type": "object",
            "description": "Utility fields used during processing",
            "example": {
              "tokenizeStrategy": "DEFAULT",
              "split": [
                {
                  "type": "CARD"
                }
              ],
              "token": "tok_1NVf4HKj8i9s3xYz"
            }
          }
        },
        "required": [
          "type",
          "items"
        ]
      },
      "payments.PaymentWithCard": {
        "type": "object",
        "properties": {
          "order": {
            "description": "Order being paid for",
            "allOf": [
              {
                "$ref": "#/components/schemas/payments.Order"
              }
            ]
          },
          "locationId": {
            "type": "string",
            "description": "Location id where the payment is attributed",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "paymentStatus": {
            "type": "string",
            "description": "Current state of the payment",
            "example": "PENDING",
            "enum": [
              "PENDING",
              "CONFIRMED"
            ]
          },
          "paymentIntent": {
            "type": "object",
            "description": "Payment intent info when finalising a previously started intent",
            "example": {
              "ids": [
                "pi_1NVf4HKj8i9s3xYz"
              ],
              "status": "SUCCEEDED"
            }
          }
        },
        "required": [
          "order",
          "locationId",
          "paymentStatus"
        ]
      },
      "payments.ValidateMerchantPayload": {
        "type": "object",
        "properties": {
          "validationURL": {
            "type": "string",
            "description": "Apple Pay merchant validation URL returned by the browser",
            "example": "https://apple-pay-gateway.apple.com/paymentservices/startSession"
          }
        },
        "required": [
          "validationURL"
        ]
      },
      "payments.FulfillTransaction": {
        "type": "object",
        "properties": {}
      },
      "payments.ProcessGlovoTransaction": {
        "type": "object",
        "properties": {}
      },
      "payments.RefundPayload": {
        "type": "object",
        "properties": {}
      },
      "payments.CreateSource": {
        "type": "object",
        "properties": {
          "externalId": {
            "type": "string",
            "description": "External identifier for the source (e.g. provider account id)",
            "example": "glovo_store_42"
          },
          "name": {
            "type": "string",
            "description": "Human readable name of the source",
            "example": "Glovo - Sol store"
          }
        },
        "required": [
          "externalId",
          "name"
        ]
      },
      "payments.CreateDiscount": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Scope metadata describing where the discount applies",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "itemsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "mealsIds": [],
              "sources": [
                "KIOSK.",
                "POS."
              ]
            }
          },
          "name": {
            "type": "string",
            "description": "Human readable discount name",
            "example": "Student 10% Off"
          },
          "type": {
            "type": "string",
            "description": "Whether the discount is a percentage or a fixed amount",
            "example": "PERCENT",
            "enum": [
              "PERCENT",
              "FIXED"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Discount value; whole percent for PERCENT (e.g. 10 = 10%) or cents for FIXED (e.g. 1000 = 10.00)",
            "example": 10
          },
          "codes": {
            "description": "List of redemption codes customers can enter to apply the discount",
            "example": [
              "STUDENT10",
              "SCHOOL10"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "singleUse": {
            "type": "boolean",
            "description": "If true, each code can only be redeemed once per customer",
            "example": false
          },
          "appliesToBasePriceOnly": {
            "type": "boolean",
            "description": "If true, the discount applies only to each item's base price; modifiers, paid step items, and other extras are charged in full. Defaults to false (discount applies to the full line price).",
            "example": false
          },
          "appliesToSingleLine": {
            "type": "boolean",
            "description": "FIXED only: if true the whole amount comes off a SINGLE eligible line (the dearest) instead of being shared out across every eligible line. A loyalty reward sets this — \"one article free\" has to free an article, not take a third of itself off each of three döners. Defaults to false, which is the sharing behaviour every discount written before this had.",
            "example": false
          },
          "menusIds": {
            "description": "Restrict to specific menus by id",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hidden": {
            "type": "boolean",
            "description": "If true, the discount is omitted from the browsable POS list but remains redeemable by code/QR.",
            "example": false
          },
          "validFrom": {
            "type": "string",
            "description": "ISO date/time from which the discount becomes valid. Omit for no start bound.",
            "example": "2026-06-15T00:00:00.000Z"
          },
          "validUntil": {
            "type": "string",
            "description": "ISO date/time after which the discount expires. Omit for no expiry.",
            "example": "2026-12-31T23:59:59.000Z"
          },
          "usageLimit": {
            "type": "object",
            "description": "Usage caps. interval is the calendar reset period (EVER = lifetime). maxGlobal caps total redemptions; maxPerMember caps redemptions per staff member.",
            "example": {
              "interval": "DAY",
              "maxGlobal": 100,
              "maxPerMember": 1
            }
          },
          "minOrderAmount": {
            "type": "number",
            "description": "Minimum pre-discount order total (cents) required to redeem the discount. Omit for no minimum.",
            "example": 1000
          },
          "loyaltyCustomerId": {
            "type": "string",
            "description": "Loyalty customer this discount is private to. Set for promotions resolved for a specific customer; the discount is only listed when that customer is identified."
          },
          "loyaltyRewardTierId": {
            "type": "string",
            "description": "The loyalty reward tier this discount mirrors. Set only by the loyalty mirror, and what lets a redemption be recovered from the discount when the caller carries nothing but its id."
          }
        },
        "required": [
          "trace",
          "name",
          "amount"
        ]
      },
      "payments.UpdateDiscount": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Scope metadata describing where the discount applies",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "itemsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "mealsIds": [],
              "sources": [
                "KIOSK"
              ]
            }
          },
          "name": {
            "type": "string",
            "description": "Human readable discount name",
            "example": "Student 10% Off"
          },
          "type": {
            "type": "string",
            "description": "Whether the discount is a percentage or a fixed amount",
            "example": "PERCENT",
            "enum": [
              "PERCENT",
              "FIXED"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Discount value; whole percent for PERCENT (e.g. 10 = 10%) or cents for FIXED (e.g. 1500 = 15.00)",
            "example": 15
          },
          "codes": {
            "description": "List of redemption codes customers can enter to apply the discount",
            "example": [
              "STUDENT15"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "singleUse": {
            "type": "boolean",
            "description": "If true, each code can only be redeemed once per customer",
            "example": true
          },
          "appliesToBasePriceOnly": {
            "type": "boolean",
            "description": "If true, the discount applies only to each item's base price; modifiers, paid step items, and other extras are charged in full. Defaults to false (discount applies to the full line price).",
            "example": true
          },
          "menusIds": {
            "description": "Restrict to specific menus by id",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hidden": {
            "type": "boolean",
            "description": "If true, the discount is omitted from the browsable POS list but remains redeemable by code/QR.",
            "example": false
          },
          "validFrom": {
            "type": "string",
            "description": "ISO date/time from which the discount becomes valid. Send null to clear.",
            "example": "2026-06-15T00:00:00.000Z"
          },
          "validUntil": {
            "type": "string",
            "description": "ISO date/time after which the discount expires. Send null to clear.",
            "example": "2026-12-31T23:59:59.000Z"
          },
          "usageLimit": {
            "type": "object",
            "description": "Usage caps. interval is the calendar reset period (EVER = lifetime). maxGlobal caps total redemptions; maxPerMember caps redemptions per staff member.",
            "example": {
              "interval": "DAY",
              "maxGlobal": 100,
              "maxPerMember": 1
            }
          },
          "minOrderAmount": {
            "type": "number",
            "description": "Minimum pre-discount order total (cents) required to redeem the discount. Send null to clear.",
            "example": 1000
          }
        }
      },
      "payments.CreateTax": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Scope metadata (locations and external tax/account ids)",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "taxId": "txr_1NVf4HKj8i9s3xYz",
              "accountId": "acct_1NVf4HKj8i9s3xYz"
            }
          },
          "name": {
            "type": "string",
            "description": "Human readable tax name",
            "example": "IVA 10%"
          },
          "description": {
            "type": "string",
            "description": "Optional description shown to merchants",
            "example": "Spanish reduced VAT for hospitality"
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          },
          "type": {
            "type": "string",
            "description": "Tax computation type: PERCENT (basis points) or FIXED (cents)",
            "example": "PERCENT",
            "enum": [
              "PERCENT",
              "FIXED"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Tax value; basis points for PERCENT (1000 = 10%) or cents for FIXED",
            "example": 1000
          },
          "min": {
            "type": "number",
            "description": "Optional minimum tax amount in cents",
            "example": 0
          },
          "max": {
            "type": "number",
            "description": "Optional maximum tax cap in cents",
            "example": 10000
          },
          "default": {
            "type": "boolean",
            "description": "Marks this tax as the company default, applied to transactions created without item-level taxes (gateway webhooks, integrations)",
            "example": true
          }
        },
        "required": [
          "trace",
          "name",
          "currency",
          "type",
          "amount"
        ]
      },
      "payments.UpdateTax": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the tax record to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "trace": {
            "type": "object",
            "description": "Scope metadata (locations and external tax/account ids)",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "taxId": "txr_1NVf4HKj8i9s3xYz",
              "accountId": "acct_1NVf4HKj8i9s3xYz"
            }
          },
          "name": {
            "type": "string",
            "description": "Human readable tax name",
            "example": "IVA 10%"
          },
          "description": {
            "type": "string",
            "description": "Optional description shown to merchants",
            "example": "Spanish reduced VAT for hospitality"
          },
          "type": {
            "type": "string",
            "description": "Tax computation type: PERCENT (basis points) or FIXED (cents)",
            "example": "PERCENT",
            "enum": [
              "PERCENT",
              "FIXED"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Tax value; basis points for PERCENT (1000 = 10%) or cents for FIXED",
            "example": 1000
          },
          "min": {
            "type": "number",
            "description": "Optional minimum tax amount in cents",
            "example": 0
          },
          "max": {
            "type": "number",
            "description": "Optional maximum tax cap in cents",
            "example": 10000
          },
          "default": {
            "type": "boolean",
            "description": "Marks this tax as the company default, applied to transactions created without item-level taxes (gateway webhooks, integrations). Setting it to true unflags the other taxes of the company.",
            "example": true
          }
        },
        "required": [
          "id",
          "trace",
          "name",
          "type",
          "amount"
        ]
      },
      "payments.CreateFee": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Location scope and provider the fee applies to",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "provider": "GLOVO"
            }
          },
          "name": {
            "type": "string",
            "description": "Human readable fee name",
            "example": "Delivery Service Fee"
          },
          "description": {
            "type": "string",
            "description": "Optional description shown to merchants",
            "example": "Glovo commission on delivery orders"
          },
          "type": {
            "type": "string",
            "description": "Fee computation type: PERCENT (basis points) or FIXED (cents)",
            "example": "PERCENT",
            "enum": [
              "PERCENT",
              "FIXED"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Fee value; basis points for PERCENT (1000 = 10%) or cents for FIXED",
            "example": 3000
          },
          "min": {
            "type": "number",
            "description": "Optional minimum fee in cents",
            "example": 100
          },
          "max": {
            "type": "number",
            "description": "Optional maximum fee cap in cents",
            "example": 5000
          }
        },
        "required": [
          "trace",
          "name",
          "type",
          "amount"
        ]
      },
      "payments.UpdateFee": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the fee to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "trace": {
            "type": "object",
            "description": "Location scope and provider the fee applies to",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "provider": "GLOVO"
            }
          },
          "name": {
            "type": "string",
            "description": "Human readable fee name",
            "example": "Delivery Service Fee"
          },
          "description": {
            "type": "string",
            "description": "Optional description shown to merchants",
            "example": "Glovo commission on delivery orders"
          },
          "type": {
            "type": "string",
            "description": "Fee computation type: PERCENT (basis points) or FIXED (cents)",
            "example": "PERCENT",
            "enum": [
              "PERCENT",
              "FIXED"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Fee value; basis points for PERCENT (1000 = 10%) or cents for FIXED",
            "example": 2500
          },
          "min": {
            "type": "number",
            "description": "Optional minimum fee in cents",
            "example": 100
          },
          "max": {
            "type": "number",
            "description": "Optional maximum fee cap in cents",
            "example": 5000
          }
        },
        "required": [
          "id",
          "trace",
          "name",
          "type",
          "amount"
        ]
      },
      "payments.CreateCashRegister": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Devices and location the cash register is bound to",
            "example": {
              "devicesIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0",
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d2"
            }
          }
        },
        "required": [
          "trace"
        ]
      },
      "payments.OpenCashRegister": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "Optional note about the opening (e.g. shift, reason)",
            "example": "Morning shift"
          },
          "amount": {
            "type": "number",
            "description": "Initial float placed in the drawer, in minor units (cents)",
            "example": 10000
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "payments.CloseCashRegister": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "Optional note explaining the closing conditions",
            "example": "End of evening shift"
          },
          "amount": {
            "type": "number",
            "description": "Cash counted at close, in minor units (cents)",
            "example": 18750
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "payments.TrackCashRegisterTransaction": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "Optional description or note for the tracked movement",
            "example": "Cash tip handed to courier"
          },
          "trace": {
            "type": "object",
            "description": "Trace metadata linking the movement to an order",
            "example": {
              "orderId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          },
          "type": {
            "type": "string",
            "description": "Cash movement type",
            "example": "SALE",
            "enum": [
              "SETUP",
              "SALE",
              "REFUND",
              "INCOME",
              "OUTCOME",
              "CHANGE",
              "CHANGE_KEEPED",
              "OPENED",
              "ADJUSTMENT",
              "MACHINE_DEPOSIT",
              "MACHINE_WITHDRAWAL"
            ]
          },
          "amount": {
            "type": "number",
            "description": "Amount in minor units (cents); positive for inflows, negative for outflows",
            "example": 1250
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          }
        },
        "required": [
          "trace",
          "type",
          "amount",
          "currency"
        ]
      },
      "payments.UpdateSnapshotEntry": {
        "type": "object",
        "properties": {
          "createdAt": {
            "type": "object",
            "description": "When the cash movement happened",
            "example": "2026-04-23T12:00:00.000Z"
          },
          "amount": {
            "type": "number",
            "description": "Amount of the entry in minor units (cents)",
            "example": 500
          },
          "description": {
            "type": "string",
            "description": "Optional description or note",
            "example": "Tip from customer"
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          }
        }
      },
      "payments.UpdateCashSnapshot": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "Optional description or note about the snapshot",
            "example": "Corrected closing amount after recount"
          },
          "notifyAlert": {
            "type": "boolean",
            "description": "Whether to raise an alert notification",
            "example": false
          },
          "openedAt": {
            "type": "object",
            "description": "When the register was opened",
            "example": "2026-04-23T09:00:00.000Z"
          },
          "closedAt": {
            "type": "object",
            "description": "When the register was closed",
            "example": "2026-04-23T21:00:00.000Z"
          },
          "transactions": {
            "type": "number",
            "description": "Total number of transactions in the shift",
            "example": 42
          },
          "initialAmount": {
            "type": "number",
            "description": "Initial cash in drawer (cents)",
            "example": 10000
          },
          "salesAmount": {
            "type": "number",
            "description": "Sum of sales during the shift (cents)",
            "example": 152500
          },
          "refundsAmount": {
            "type": "number",
            "description": "Sum of refunds issued during the shift (cents)",
            "example": 1500
          },
          "changeGivenAmount": {
            "type": "number",
            "description": "Sum of change returned during the shift (cents)",
            "example": 3200
          },
          "changeKeepedAmount": {
            "type": "number",
            "description": "Sum of change kept (left by customers) during the shift (cents)",
            "example": 450
          },
          "incomesAmount": {
            "type": "number",
            "description": "Sum of ad-hoc cash income (cents)",
            "example": 0
          },
          "outcomesAmount": {
            "type": "number",
            "description": "Sum of ad-hoc cash outflows (cents)",
            "example": 2000
          },
          "machineDepositsAmount": {
            "type": "number",
            "description": "Sum of cash swept from the drawer into a linked cash machine during the shift (cents)",
            "example": 0
          },
          "machineWithdrawalsAmount": {
            "type": "number",
            "description": "Sum of cash dispensed by a linked cash machine instead of a manual outcome during the shift (cents)",
            "example": 0
          },
          "expectedAmount": {
            "type": "number",
            "description": "Expected cash in drawer at close (cents)",
            "example": 156250
          },
          "availableAmount": {
            "type": "number",
            "description": "Counted cash in drawer at close (cents)",
            "example": 156200
          },
          "diffInitialAmount": {
            "type": "number",
            "description": "Difference on opening (cents, + over, - under)",
            "example": 0
          },
          "diffFinalAmount": {
            "type": "number",
            "description": "Difference on close (cents, + over, - under)",
            "example": -50
          },
          "openingsSnapshots": {
            "description": "Opening entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          },
          "refundsSnapshots": {
            "description": "Refund entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          },
          "changeKeepedSnapshots": {
            "description": "Change-kept entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          },
          "incomesSnapshots": {
            "description": "Income entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          },
          "outcomesSnapshots": {
            "description": "Outcome entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          },
          "machineDepositsSnapshots": {
            "description": "Machine-deposit entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          },
          "machineWithdrawalsSnapshots": {
            "description": "Machine-withdrawal entries breakdown",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.UpdateSnapshotEntry"
            }
          }
        }
      },
      "payments.CreateSnapshotFix": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "Human readable reason for recording the fix",
            "example": "Counted 5 EUR difference due to bill misread"
          },
          "notifyAlert": {
            "type": "boolean",
            "description": "Whether to raise an alert notification to the company staff",
            "example": true
          }
        },
        "required": [
          "description"
        ]
      },
      "payments.SubscriberPayload": {
        "type": "object",
        "properties": {
          "programId": {
            "type": "string",
            "description": "Id of the loyalty/subscription program to join",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "templateId": {
            "type": "string",
            "description": "Id of the program template/tier being subscribed to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "provider": {
            "type": "string",
            "description": "Payment provider used to complete the subscription",
            "example": "STRIPE"
          },
          "args": {
            "type": "object",
            "description": "Provider-specific payload (e.g. Stripe sessionId)",
            "example": {
              "sessionId": "cs_test_a1b2c3d4"
            }
          },
          "returnUrl": {
            "type": "string",
            "description": "URL the customer is returned to after the provider flow",
            "example": "https://shop.platomico.com/account/subscription/success"
          }
        },
        "required": [
          "programId",
          "templateId",
          "provider",
          "args"
        ]
      },
      "payments.FetchStatus": {
        "type": "object",
        "properties": {}
      },
      "payments.ExternalPayload": {
        "type": "object",
        "properties": {}
      },
      "payments.UpdateSubscription": {
        "type": "object",
        "properties": {}
      },
      "payments.SubscriptionPayload": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name of the subscription product",
            "example": "Platomico Premium"
          },
          "description": {
            "type": "string",
            "description": "Marketing description shown to customers",
            "example": "Unlock member-only discounts and priority support."
          },
          "image": {
            "type": "string",
            "description": "Image URL for the subscription product card",
            "example": "https://cdn.platomico.com/products/premium.png"
          },
          "items": {
            "description": "Price tiers and their external price ids",
            "example": [
              {
                "price": {
                  "amount": 999,
                  "currency": "EUR"
                },
                "externalId": "price_1NVf4HKj8i9s3xYz"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "provider": {
            "type": "string",
            "description": "Payment provider managing the subscription",
            "example": "STRIPE"
          },
          "locationsIds": {
            "description": "Locations where the subscription is offered",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "description",
          "image",
          "items",
          "provider",
          "locationsIds"
        ]
      },
      "payments.SubscriptionSession": {
        "type": "object",
        "properties": {
          "subscriptionId": {
            "type": "string",
            "description": "Id of the subscription product the customer wants to buy",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "config": {
            "type": "object",
            "description": "Redirect URLs the provider should use after checkout",
            "example": {
              "success_url": "https://shop.platomico.com/account/subscription/success",
              "cancel_url": "https://shop.platomico.com/account/subscription/cancel"
            }
          }
        },
        "required": [
          "subscriptionId",
          "config"
        ]
      },
      "payments.CustomerPortal": {
        "type": "object",
        "properties": {
          "returnUrl": {
            "type": "string",
            "description": "URL the customer portal redirects back to after the session ends",
            "example": "https://shop.platomico.com/account"
          },
          "customerId": {
            "type": "string",
            "description": "Provider customer id to open the portal for",
            "example": "cus_1NVf4HKj8i9s3xYz"
          }
        },
        "required": [
          "returnUrl",
          "customerId"
        ]
      },
      "payments.Charge": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount to charge, in minor units (cents)",
            "example": 1250
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "payments.Benefit": {
        "type": "object",
        "properties": {}
      },
      "payments.Item": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "description": "Id of the parent order this item belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "hash": {
            "type": "string",
            "description": "Deterministic hash of the item (id + modifiers) used for deduplication",
            "example": "f8e4c0b2a19d"
          },
          "type": {
            "type": "string",
            "description": "Whether the row refers to a catalog item, a composed meal, or an EXTERNAL line — one with no catalog document behind it, priced at face value from its own `price`. A custom amount typed at the till is an EXTERNAL line",
            "example": "ITEM",
            "enum": [
              "ITEM",
              "MEAL",
              "EXTERNAL"
            ]
          },
          "id": {
            "type": "string",
            "description": "Catalog item or meal id. A custom amount carries the CUSTOM_LINE_ID sentinel, so every one groups together in reporting instead of scattering",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "name": {
            "type": "string",
            "description": "Human readable item name (cached from catalog)",
            "example": "Margherita Pizza"
          },
          "quantity": {
            "type": "number",
            "description": "Number of units of this item",
            "example": 2
          },
          "menuId": {
            "type": "string",
            "description": "Menu this line was sold from. When that menu carries a price override for the product, it becomes the base price of the line instead of the catalog price. Absent (or a menu with no override) keeps the catalog price.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d3"
          },
          "modifiers": {
            "description": "Selected modifiers with their quantities and optional prices",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                "quantity": 1,
                "name": "Extra cheese",
                "unitPrice": {
                  "amount": 150,
                  "currency": "EUR"
                },
                "price": {
                  "amount": 150,
                  "currency": "EUR"
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unitPrice": {
            "type": "object",
            "description": "Unit price before multiplying by quantity",
            "example": {
              "amount": 1250,
              "currency": "EUR"
            }
          },
          "price": {
            "type": "object",
            "description": "Final line price (unitPrice * quantity + modifiers)",
            "example": {
              "amount": 2500,
              "currency": "EUR"
            }
          },
          "steps": {
            "description": "Nested item steps (for meals composed of groups of items)",
            "example": [],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "benefit": {
            "description": "Benefit (loyalty reward) applied to this line if any",
            "allOf": [
              {
                "$ref": "#/components/schemas/payments.Benefit"
              }
            ]
          },
          "note": {
            "type": "string",
            "description": "Free-form note attached to this line (e.g. for the kitchen)",
            "example": "No onions"
          },
          "taxes": {
            "description": "Tax ids to apply to this line. EXTERNAL lines only — every other type reads its taxes off the catalog document, which an EXTERNAL line does not have. An empty array means no tax; omitting it falls back to the company default tax",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "orderId",
          "hash",
          "type",
          "id",
          "quantity",
          "modifiers",
          "price",
          "steps"
        ]
      },
      "payments.CustomCharge": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount to charge, in minor units (cents). Must be a positive integer — this is the exact figure the terminal will ask for",
            "example": 1250
          },
          "method": {
            "type": "string",
            "description": "How the money is taken",
            "example": "CARD",
            "enum": [
              "CARD",
              "CASH",
              "CARD_MANUAL"
            ]
          },
          "label": {
            "type": "string",
            "description": "What the line reads on the ticket. Defaults to \"Custom amount\" when absent or blank",
            "example": "Custom amount"
          },
          "taxId": {
            "type": "string",
            "description": "Tax to apply. Omit to fall back to the company default tax; pass null to charge with no tax at all",
            "example": "64f1b8a2c3d4e5f6a7b8c9d4",
            "nullable": true
          },
          "tendered": {
            "type": "number",
            "description": "What the customer handed over, in minor units. CASH only — change is computed from it",
            "example": 2000
          },
          "note": {
            "type": "string",
            "description": "Free-form note carried to the kitchen ticket and the receipt",
            "example": "Deposit for the Saturday booking"
          },
          "type": {
            "type": "string",
            "description": "Fulfillment type recorded on the sale",
            "example": "TAKE_AWAY"
          }
        },
        "required": [
          "amount",
          "method"
        ]
      },
      "payments.CreateReview": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "description": "Id of the transaction the review is attached to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "rating": {
            "type": "number",
            "description": "Star rating (typically 1-5)",
            "example": 5
          },
          "comment": {
            "type": "string",
            "description": "Free-form review text",
            "example": "Great food, fast service!"
          }
        },
        "required": [
          "transactionId"
        ]
      },
      "payments.FixTransaction": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Id of the company whose transactions should be reconciled",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "from": {
            "type": "string",
            "description": "Start of date range (ISO string)",
            "example": "2026-04-01T00:00:00.000Z"
          },
          "to": {
            "type": "string",
            "description": "End of date range (ISO string)",
            "example": "2026-04-30T23:59:59.999Z"
          },
          "paymentId": {
            "type": "string",
            "description": "Id of the payment to reconcile",
            "example": "pi_1NVf4HKj8i9s3xYz"
          },
          "source": {
            "type": "string",
            "description": "Source/channel the transactions originated from",
            "example": "POS."
          }
        },
        "required": [
          "companyId",
          "from",
          "to",
          "paymentId",
          "source"
        ]
      },
      "payments.RefundPayloadV2": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Id of the company issuing the refund",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "paymentId": {
            "type": "string",
            "description": "Id of the payment being refunded",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "amount": {
            "type": "number",
            "description": "Refund amount in minor units (cents)",
            "example": 1250
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          },
          "reason": {
            "type": "string",
            "description": "Human readable reason for the refund",
            "example": "Customer requested refund - wrong order"
          },
          "requestedBy": {
            "type": "string",
            "description": "Identifier of the member/user who requested the refund",
            "example": "user@platomico.com"
          },
          "accountId": {
            "type": "string",
            "description": "Optional processor account id when operating under a connect/platform account",
            "example": "acct_1NVf4HKj8i9s3xYz"
          },
          "deviceId": {
            "type": "string",
            "description": "Device issuing the refund. Only used to pick which cash machine pays out a CASH refund — the till standing in front of the customer. Falls back to the device that took the sale.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d2"
          }
        },
        "required": [
          "companyId",
          "paymentId",
          "amount",
          "currency"
        ]
      },
      "payments.PrintReceiptDto": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "description": "Id of the transaction whose receipt should be printed",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "template": {
            "type": "string",
            "description": "Receipt template to use",
            "example": "default"
          },
          "receiverId": {
            "type": "string",
            "description": "Id of the receiver device/printer",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "args": {
            "type": "object",
            "description": "Extra template arguments passed through to the renderer",
            "example": {
              "locale": "es",
              "copy": "merchant"
            }
          }
        },
        "required": [
          "transactionId"
        ]
      },
      "payments.PushPrintDto": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "description": "Id of the transaction whose receipt should be printed",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "deviceId": {
            "type": "string",
            "description": "Id of the target printer device that should receive the print job. When omitted, the receiver is resolved server-side: a printer linked to the calling device first, else the location printer with a listener.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "templates": {
            "type": "array",
            "description": "Templates to print for this transaction",
            "example": [
              "PRINT_RECEIPT"
            ],
            "default": [
              "PRINT_RECEIPT"
            ],
            "items": {
              "type": "string",
              "enum": [
                "PRINT_RECEIPT",
                "PRINT_KITCHEN_RECEIPT"
              ]
            }
          },
          "args": {
            "type": "object",
            "description": "Extra template arguments passed through to the renderer",
            "example": {
              "locale": "es",
              "copy": "merchant"
            }
          }
        },
        "required": [
          "transactionId"
        ]
      },
      "payments.FulFillTransactionDto": {
        "type": "object",
        "properties": {}
      },
      "payments.CreateTransactionV3Dto": {
        "type": "object",
        "properties": {}
      },
      "payments.Step": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Optional human readable name of the step",
            "example": "Charge card"
          },
          "action": {
            "type": "string",
            "description": "Action executed by this step",
            "example": "PROCESS_PAYMENT",
            "enum": [
              "PROCESS_PAYMENT",
              "PROCESS_PAYMENT_INTENT",
              "PUSH_ORDER_TO_KDS",
              "SEND_EMAIL",
              "SEND_SMS",
              "PRINT",
              "WEBHOOK",
              "VERIFY_CUSTOMER",
              "SUBSCRIBE_CUSTOMER",
              "CREATE_WALLET_PASS",
              "CREATE_TRANSACTION",
              "CONSUME_INVENTORY"
            ]
          },
          "args": {
            "type": "object",
            "description": "Action-specific payload",
            "example": {
              "template": "receipt-default"
            }
          },
          "settings": {
            "type": "object",
            "description": "Step execution settings",
            "example": {
              "conditions": [],
              "concurrent": false,
              "allowToFail": false,
              "return": true
            }
          }
        },
        "required": [
          "action",
          "settings"
        ]
      },
      "payments.CreateFlow": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human readable flow name",
            "example": "Default checkout flow"
          },
          "description": {
            "type": "string",
            "description": "Optional description of the flow",
            "example": "Standard card + cash split with tip prompt"
          },
          "trace": {
            "type": "object",
            "description": "Scope metadata (locations and sources this flow applies to)",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "sources": [
                "POS.",
                "KIOSK."
              ]
            }
          },
          "useCase": {
            "type": "string",
            "description": "Use case this flow is intended for",
            "example": "CARD",
            "enum": [
              "ANY",
              "CASH",
              "SPLIT_CARD",
              "SPLIT",
              "CARD",
              "SUBSCRIPTION"
            ]
          },
          "steps": {
            "description": "Ordered list of steps executed during the flow",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.Step"
            }
          }
        },
        "required": [
          "name",
          "trace",
          "useCase",
          "steps"
        ]
      },
      "payments.CreateTable": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Mesa 4"
          },
          "zone": {
            "type": "string",
            "example": "Terraza"
          },
          "seats": {
            "type": "number",
            "example": 4
          }
        },
        "required": [
          "name"
        ]
      },
      "payments.UpdateTable": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Mesa 4"
          },
          "zone": {
            "type": "string",
            "example": "Terraza"
          },
          "seats": {
            "type": "number",
            "example": 4
          },
          "active": {
            "type": "boolean",
            "example": false,
            "description": "Set to false to archive the table (blocked while occupied)"
          }
        }
      },
      "payments.CashDenomination": {
        "type": "object",
        "properties": {
          "valueCents": {
            "type": "number",
            "description": "Face value in cents",
            "example": 200
          },
          "pieces": {
            "type": "number",
            "description": "How many of them the machine holds",
            "example": 14
          },
          "unit": {
            "type": "number",
            "description": "Which unit holds it. On a Glory CI-10, 1 is the note recycler and 2 the coin recycler — the split that decides whether the machine can make change.",
            "example": 2
          }
        },
        "required": [
          "valueCents",
          "pieces",
          "unit"
        ]
      },
      "payments.ReportCashInventoryRequest": {
        "type": "object",
        "properties": {
          "cashMachineId": {
            "type": "string",
            "description": "Cash machine the reading came from",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0"
          },
          "totalCents": {
            "type": "number",
            "description": "Total held, in cents",
            "example": 13837
          },
          "currency": {
            "type": "string",
            "description": "Currency of the amounts",
            "example": "EUR"
          },
          "denominations": {
            "description": "Everything the machine is holding, per denomination",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.CashDenomination"
            }
          }
        },
        "required": [
          "cashMachineId",
          "totalCents",
          "currency",
          "denominations"
        ]
      },
      "payments.CashChargeProgress": {
        "type": "object",
        "properties": {
          "insertedTotal": {
            "type": "number",
            "description": "Cash inserted so far, in cents, as reported by the machine.",
            "example": 500
          },
          "awaitingRemoval": {
            "type": "boolean",
            "description": "True while the machine is holding dispensed change and waiting for it to be taken. It does NOT answer the charge until the tray is emptied, so without this the screen shows a spinner while the money sits in front of the customer.",
            "example": false
          }
        },
        "required": [
          "insertedTotal"
        ]
      },
      "payments.PostCashJobResult": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "description": "Outcome as observed by the till. SUCCESS means the machine completed the operation; FAILURE means it refused, faulted or was unreachable.",
            "enum": [
              "SUCCESS",
              "FAILURE"
            ],
            "example": "SUCCESS"
          },
          "receivedTotal": {
            "type": "number",
            "description": "Cash the machine took in, in cents. Becomes the recorded tender, so it must come from the machine and never from operator input.",
            "example": 2000
          },
          "dispensedTotal": {
            "type": "number",
            "description": "Cash the machine paid out, in cents. Becomes the recorded change.",
            "example": 766
          },
          "code": {
            "type": "string",
            "description": "Machine-readable failure code, mirroring the provider error tags (device_busy, device_error, unavailable, ...).",
            "example": "device_busy"
          },
          "reason": {
            "type": "string",
            "description": "Human-readable failure reason for the operator and the logs.",
            "example": "The cash device is not idle (busy with another operation)"
          },
          "deviceStatus": {
            "type": "object",
            "description": "Raw device status when the machine itself reported a fault.",
            "example": {
              "status": 2,
              "statusText": "Note jam"
            }
          }
        },
        "required": [
          "state"
        ]
      },
      "payments.CreateCashChargeRequest": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount to collect, in integer cents",
            "example": 1234
          },
          "currency": {
            "type": "string",
            "description": "3-letter ISO currency; must match the location currency",
            "example": "EUR"
          },
          "order": {
            "description": "The order to record once the cash is confirmed. Omit when charging a custom amount — the server builds the one-line order itself.",
            "allOf": [
              {
                "$ref": "#/components/schemas/payments.Order"
              }
            ]
          },
          "customAmount": {
            "type": "object",
            "description": "Charge an operator-typed amount instead of a cart. When present the server builds the single CUSTOM line, so `order` is ignored and `amount` is what is charged.",
            "example": {
              "label": "Custom amount",
              "taxId": "64f1b8a2c3d4e5f6a7b8c9d4"
            }
          },
          "openTableTransactionId": {
            "type": "string",
            "description": "Open-table transaction to complete, when the cash settles an existing bill. Omit for a direct sale.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "amount"
        ]
      },
      "payments.CashChargeView": {
        "type": "object",
        "properties": {
          "cashChargeId": {
            "type": "string",
            "description": "Cash charge identifier, used to poll and to cancel",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "transactionId": {
            "type": "string",
            "description": "Transaction the sale will be recorded under. Minted up front so the client knows it before the customer has paid.",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0"
          },
          "status": {
            "type": "string",
            "description": "PENDING (waiting for the till) · RUNNING (customer inserting) · SETTLING (recording the sale) · COMPLETED (paid and recorded) · FAILURE · EXPIRED · CANCELED",
            "example": "RUNNING"
          },
          "amount": {
            "type": "number",
            "description": "Amount to collect, in cents",
            "example": 1234
          },
          "currency": {
            "type": "string",
            "description": "Currency of the charge",
            "example": "EUR"
          },
          "insertedTotal": {
            "type": "number",
            "description": "How much the customer has inserted so far, in cents. Progress only — the outcome always comes from the machine total on settlement.",
            "example": 500
          },
          "receivedTotal": {
            "type": "number",
            "description": "Cash the machine took, in cents. Present once settled.",
            "example": 2000
          },
          "dispensedTotal": {
            "type": "number",
            "description": "Change the machine dispensed, in cents. Present once settled.",
            "example": 766
          },
          "code": {
            "type": "string",
            "description": "Machine-readable failure code when the charge did not complete (device_error, not_ready, timeout, canceled, ...).",
            "example": "not_ready"
          },
          "reason": {
            "type": "string",
            "description": "Operator-facing explanation, including the physical action needed when the machine is not ready.",
            "example": "The machine needs attention: WAITING_CASH_IN_REMOVE. Remove the cash left in the input tray."
          },
          "needsReconciliation": {
            "type": "boolean",
            "description": "True when the machine took the money but the sale could not be recorded. Needs reconciliation — never shown as a clean success.",
            "example": false
          },
          "awaitingCashRemoval": {
            "type": "boolean",
            "description": "True while the machine is waiting for its dispensed change to be taken. The charge cannot finish until it is — the client should say so rather than keep spinning.",
            "example": false
          }
        },
        "required": [
          "cashChargeId",
          "transactionId",
          "status",
          "amount",
          "currency",
          "insertedTotal"
        ]
      },
      "payments.CreateCashDepositRequest": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount the operator intends to deposit, in integer cents",
            "example": 5000
          },
          "currency": {
            "type": "string",
            "description": "3-letter ISO currency; must match the location currency",
            "example": "EUR"
          },
          "description": {
            "type": "string",
            "description": "Optional note recorded on the resulting ledger movement",
            "example": "Drawer sweep before close"
          }
        },
        "required": [
          "amount"
        ]
      },
      "payments.CashDepositView": {
        "type": "object",
        "properties": {
          "cashDepositId": {
            "type": "string",
            "description": "Cash deposit identifier, used to poll and to cancel",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "status": {
            "type": "string",
            "description": "PENDING (waiting for the till) · RUNNING (operator feeding cash) · SETTLING (recording the movement) · COMPLETED (in the machine and recorded) · FAILURE · EXPIRED · CANCELED",
            "example": "RUNNING"
          },
          "amount": {
            "type": "number",
            "description": "Amount the operator declared they intend to deposit, in integer cents. This is the target the machine drives toward — any excess fed in is dispensed back as change.",
            "example": 5000
          },
          "currency": {
            "type": "string",
            "description": "Currency of the deposit",
            "example": "EUR"
          },
          "insertedTotal": {
            "type": "number",
            "description": "How much has been inserted so far, in cents. Progress only.",
            "example": 2000
          },
          "receivedTotal": {
            "type": "number",
            "description": "Cash the machine took in, in cents. Present once settled.",
            "example": 5000
          },
          "dispensedTotal": {
            "type": "number",
            "description": "Change the machine dispensed back, in cents. Present once settled. The ledger movement books receivedTotal minus this — the net actually kept.",
            "example": 0
          },
          "awaitingCashRemoval": {
            "type": "boolean",
            "description": "True while the machine is holding dispensed change and waiting for it to be taken. The deposit cannot finish until it is.",
            "example": false
          },
          "code": {
            "type": "string",
            "description": "Machine-readable failure code when the deposit did not complete (device_error, not_ready, timeout, canceled, unknown, ...).",
            "example": "not_ready"
          },
          "reason": {
            "type": "string",
            "description": "Operator-facing explanation, including the physical action needed when the machine is not ready."
          },
          "needsReconciliation": {
            "type": "boolean",
            "description": "True when the machine took the money but the register ledger could not be updated. Needs reconciliation — never shown as a clean success.",
            "example": false
          }
        },
        "required": [
          "cashDepositId",
          "status",
          "amount",
          "currency",
          "insertedTotal"
        ]
      },
      "payments.CreateCashWithdrawalRequest": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount the operator intends to withdraw, in integer cents",
            "example": 5000
          },
          "currency": {
            "type": "string",
            "description": "3-letter ISO currency; must match the location currency",
            "example": "EUR"
          },
          "description": {
            "type": "string",
            "description": "Optional note recorded on the resulting ledger movement",
            "example": "Cash pickup"
          }
        },
        "required": [
          "amount"
        ]
      },
      "payments.CashWithdrawalView": {
        "type": "object",
        "properties": {
          "cashWithdrawalId": {
            "type": "string",
            "description": "Cash withdrawal identifier, used to poll and to cancel",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "status": {
            "type": "string",
            "description": "PENDING (waiting for the till) · RUNNING (machine dispensing) · SETTLING (recording the movement) · COMPLETED (dispensed and recorded) · FAILURE · EXPIRED · CANCELED",
            "example": "RUNNING"
          },
          "amount": {
            "type": "number",
            "description": "Amount the operator intends to withdraw, in integer cents",
            "example": 5000
          },
          "currency": {
            "type": "string",
            "description": "Currency of the withdrawal",
            "example": "EUR"
          },
          "dispensedTotal": {
            "type": "number",
            "description": "Cash the machine actually paid out, in cents. Present once settled.",
            "example": 5000
          },
          "code": {
            "type": "string",
            "description": "Machine-readable failure code when the withdrawal did not complete (device_error, not_ready, timeout, canceled, unknown, ...).",
            "example": "not_ready"
          },
          "reason": {
            "type": "string",
            "description": "Operator-facing explanation, including the physical action needed when the machine is not ready."
          },
          "needsReconciliation": {
            "type": "boolean",
            "description": "True when the machine dispensed the cash but the register ledger could not be updated. Needs reconciliation — never shown as a clean success.",
            "example": false
          }
        },
        "required": [
          "cashWithdrawalId",
          "status",
          "amount",
          "currency"
        ]
      },
      "payments.CashMachineInventoryView": {
        "type": "object",
        "properties": {
          "cashMachineId": {
            "type": "string",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0"
          },
          "heldTotal": {
            "type": "number",
            "description": "Total cash inside the machine, in cents",
            "example": 13837
          },
          "notesTotal": {
            "type": "number",
            "description": "Of the held total, how much is in notes",
            "example": 7500
          },
          "coinsTotal": {
            "type": "number",
            "description": "Of the held total, how much is in coins. This is what limits change and refunds — a machine full of notes still cannot pay out 90 cents.",
            "example": 6337
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          },
          "denominations": {
            "description": "Everything the machine holds, per denomination",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.CashDenomination"
            }
          },
          "inFlightTotal": {
            "type": "number",
            "description": "Cash currently being collected or paid out by unfinished operations, in cents. Not part of the held total.",
            "example": 250
          },
          "inFlightCount": {
            "type": "number",
            "description": "How many operations that in-flight figure covers",
            "example": 1
          },
          "reportedAt": {
            "type": "string",
            "description": "When the till last read the machine",
            "example": "2026-07-29T08:37:03.000Z"
          },
          "stale": {
            "type": "boolean",
            "description": "True when no recent reading exists — the till driving this machine is not reporting, so the figure is the last known one rather than the current one.",
            "example": false
          }
        },
        "required": [
          "cashMachineId",
          "heldTotal",
          "notesTotal",
          "coinsTotal",
          "currency",
          "denominations",
          "inFlightTotal",
          "inFlightCount",
          "stale"
        ]
      },
      "payments.ClaimLoyaltyPointsRequest": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "description": "Transaction to credit. Must belong to the signed-in customer session company.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "transactionId"
        ]
      },
      "payments.ClaimLoyaltyPointsResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Outcome of the claim"
          },
          "points": {
            "type": "number",
            "description": "Points credited, when the provider reports a count. Square returns a delta; Comeback accrues on its own side and reports none."
          },
          "enrolled": {
            "type": "boolean",
            "description": "Whether a loyalty account was created for this customer"
          }
        },
        "required": [
          "status"
        ]
      },
      "payments.LoyaltyCartLineDto": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitAmount": {
            "type": "number"
          }
        },
        "required": [
          "reference",
          "name",
          "quantity",
          "unitAmount"
        ]
      },
      "payments.ResolveLoyaltyRequest": {
        "type": "object",
        "properties": {
          "identifier": {
            "type": "string",
            "description": "Customer lookup value: phone number, email, Comeback customer id, or scanned pass/QR code."
          },
          "phoneNumber": {
            "type": "string",
            "description": "Deprecated: use identifier. Kept for backward compatibility.",
            "deprecated": true
          },
          "cart": {
            "description": "Current cart lines, used to price applicable promotions",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.LoyaltyCartLineDto"
            }
          }
        },
        "required": [
          "identifier"
        ]
      },
      "payments.SplitSessionBill": {
        "type": "object",
        "properties": {}
      },
      "payments.CreateSplitSessionPlanLeg": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "example": 1500,
            "description": "Amount in minor units (cents)"
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          },
          "itemsIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "payments.CreateSplitSessionPlan": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "PERSON",
              "AMOUNT",
              "ITEMS"
            ]
          },
          "legs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.CreateSplitSessionPlanLeg"
            }
          }
        },
        "required": [
          "mode",
          "legs"
        ]
      },
      "payments.CreateSplitSession": {
        "type": "object",
        "properties": {
          "bill": {
            "$ref": "#/components/schemas/payments.SplitSessionBill"
          },
          "plan": {
            "$ref": "#/components/schemas/payments.CreateSplitSessionPlan"
          },
          "source": {
            "type": "string",
            "enum": [
              "POS.",
              "KIOSK."
            ]
          }
        },
        "required": [
          "bill",
          "plan",
          "source"
        ]
      },
      "payments.AppendLeg": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "example": 1500
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          }
        },
        "required": [
          "token",
          "amount",
          "currency"
        ]
      },
      "payments.ChargeLeg": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "enum": [
              "CARD",
              "CASH",
              "CARD_MANUAL"
            ]
          },
          "tendered": {
            "type": "number",
            "example": 2000
          }
        },
        "required": [
          "token",
          "method"
        ]
      },
      "payments.AbortSession": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        },
        "required": [
          "token"
        ]
      },
      "payments.FinalizeSession": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          }
        },
        "required": [
          "token"
        ]
      },
      "payments.CreateLocation": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Id of the company the location belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationId": {
            "type": "string",
            "description": "Id of the Platomico location to link",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "accountId": {
            "type": "string",
            "description": "Optional Stripe/Revolut connected account id",
            "example": "acct_1NVf4HKj8i9s3xYz"
          }
        },
        "required": [
          "companyId",
          "locationId"
        ]
      },
      "payments.CreateDomain": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Id of the company the domain should be registered for",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationId": {
            "type": "string",
            "description": "Id of the location associated with the domain",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "accountId": {
            "type": "string",
            "description": "Optional Stripe/Revolut connected account id",
            "example": "acct_1NVf4HKj8i9s3xYz"
          },
          "domain": {
            "type": "string",
            "description": "Domain to register for Apple Pay/wallet use",
            "example": "shop.platomico.com"
          }
        },
        "required": [
          "companyId",
          "locationId"
        ]
      },
      "payments.CreateReader": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Id of the company the reader belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationId": {
            "type": "string",
            "description": "Id of the location where the reader is physically installed",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "code": {
            "type": "string",
            "description": "Pairing code printed on the card reader",
            "example": "blast-cave-pony"
          },
          "accountId": {
            "type": "string",
            "description": "Optional Stripe/Revolut connected account id",
            "example": "acct_1NVf4HKj8i9s3xYz"
          }
        },
        "required": [
          "companyId",
          "locationId",
          "code"
        ]
      },
      "payments.CreateWebhook": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Id of the company the webhook belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "events": {
            "description": "Stripe event types the webhook should subscribe to",
            "example": [
              "payment_intent.succeeded",
              "charge.refunded"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "description": "HTTPS URL Stripe should POST events to",
            "example": "https://api.platomico.com/listener/webhooks/stripe/events"
          }
        },
        "required": [
          "companyId",
          "events",
          "url"
        ]
      },
      "payments.CreateAccount": {
        "type": "object",
        "properties": {}
      },
      "payments.Payout": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Provider-native payout identifier",
            "example": "po_1Nfe7y2eZvKYlo2C"
          },
          "provider": {
            "type": "string",
            "enum": [
              "DEFAULT",
              "ADYEN",
              "SQUARE",
              "STRIPE",
              "REVOLUT",
              "GLOVO",
              "CASH",
              "CARD"
            ],
            "description": "Gateway the payout was collected from",
            "example": "STRIPE"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "IN_TRANSIT",
              "PAID",
              "FAILED",
              "CANCELED",
              "UNKNOWN"
            ],
            "description": "Normalized payout status",
            "example": "PAID"
          },
          "amount": {
            "type": "number",
            "description": "Amount in the currency minor unit (e.g. cents)",
            "example": 45000
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "example": "EUR"
          },
          "createdAt": {
            "type": "string",
            "description": "When the payout was created (ISO 8601)",
            "example": "2026-06-15T09:12:00.000Z"
          },
          "arrivalDate": {
            "type": "string",
            "description": "Expected/known arrival date in the bank (ISO 8601)",
            "example": "2026-06-17T00:00:00.000Z"
          },
          "destinationType": {
            "type": "string",
            "description": "Destination kind reported by the gateway",
            "example": "bank_account"
          }
        },
        "required": [
          "id",
          "provider",
          "status",
          "amount",
          "currency",
          "createdAt"
        ]
      },
      "payments.PayoutSourceResult": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "DEFAULT",
              "ADYEN",
              "SQUARE",
              "STRIPE",
              "REVOLUT",
              "GLOVO",
              "CASH",
              "CARD"
            ],
            "example": "STRIPE"
          },
          "ok": {
            "type": "boolean",
            "description": "Whether the gateway was queried successfully",
            "example": true
          },
          "count": {
            "type": "number",
            "description": "Number of payouts collected from this gateway",
            "example": 12
          },
          "error": {
            "type": "string",
            "description": "Failure reason when `ok` is false (e.g. missing credentials)",
            "example": "Missing REVOLUT_API_SECRET_KEY secret for company 64f1b8a2c3d4"
          }
        },
        "required": [
          "provider",
          "ok",
          "count"
        ]
      },
      "payments.CollectPayoutsResult": {
        "type": "object",
        "properties": {
          "payouts": {
            "description": "All payouts merged across gateways, newest first",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.Payout"
            }
          },
          "sources": {
            "description": "Per-gateway collection outcome. Fail-open: one gateway failing does not block the others.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/payments.PayoutSourceResult"
            }
          }
        },
        "required": [
          "payouts",
          "sources"
        ]
      },
      "supply-chain.Trace": {
        "type": "object",
        "properties": {
          "sku": {
            "type": "string",
            "description": "Stock Keeping Unit",
            "example": "BURG-001"
          },
          "locationsIds": {
            "description": "Identifiers of the locations where the item is available",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1",
              "64f1b8a2c3d4e5f6a7b8c9d2"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bindingsIds": {
            "description": "Bindings ids to update after item creation",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "variationId": {
            "type": "string",
            "description": "Id of the original item this record is a variation of (e.g. protein variants of the same dish). Absent on the original item itself.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d5"
          }
        }
      },
      "supply-chain.Price": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Price amount (in currency minor unit / cents)",
            "example": 1250
          },
          "currency": {
            "type": "string",
            "description": "Currency code (ISO 4217)",
            "example": "EUR"
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "supply-chain.ConsumableEntry": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Type of consumable reference",
            "enum": [
              "INGREDIENT",
              "PREPARATION"
            ],
            "example": "INGREDIENT"
          },
          "id": {
            "type": "string",
            "description": "Identifier of the consumable",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "amount": {
            "type": "number",
            "description": "Amount of the consumable used per item",
            "example": 150
          }
        },
        "required": [
          "id",
          "amount"
        ]
      },
      "supply-chain.Item": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Company id (required for staff-created items)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "string",
            "description": "Name of the item",
            "example": "Classic Burger"
          },
          "description": {
            "type": "string",
            "description": "Description of the item",
            "example": "Beef patty, lettuce, tomato, cheddar cheese and house sauce"
          },
          "image": {
            "type": "string",
            "description": "Image URL of the item",
            "example": "https://cdn.platomico.com/items/classic-burger.jpg"
          },
          "trace": {
            "description": "Traceability information",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.Trace"
              }
            ]
          },
          "price": {
            "description": "Pricing details of the item",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.Price"
              }
            ]
          },
          "consumables": {
            "description": "List of consumables (ingredients or preparations) composing the item",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/supply-chain.ConsumableEntry"
            }
          },
          "taxes": {
            "description": "Tax ids applied to the item",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "modifiers": {
            "description": "Modifier ids associated with the item (e.g. toppings, sizes)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d5",
              "64f1b8a2c3d4e5f6a7b8c9d6"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settings": {
            "type": "object",
            "description": "Presentation settings (POS-specific)",
            "example": {
              "color": "#FFFFFF",
              "backgroundColor": "#C0392B",
              "weight": "bold",
              "max": 10
            }
          },
          "tags": {
            "description": "Tags associated with the item",
            "example": [
              "burger",
              "signature"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "Other known names of the item (used for search / binding)",
            "example": [
              "Hamburguesa Clasica",
              "House Burger"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "dietary": {
            "description": "Dietary categories applicable to the item",
            "example": [
              "HALAL"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "allergens": {
            "description": "Allergen ids associated with the item",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d7"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "section": {
            "type": "string",
            "description": "KDS grouping section (free-text label, e.g. \"Bar\", \"Cocina\")",
            "example": "Bar"
          },
          "visible": {
            "type": "boolean",
            "description": "Record-level visibility. `false` hides the item from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible.",
            "example": true
          }
        },
        "required": [
          "name",
          "trace",
          "price",
          "consumables",
          "tags",
          "knownAs"
        ]
      },
      "supply-chain.Provider": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Provider id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d3"
          },
          "name": {
            "type": "string",
            "description": "Provider name",
            "example": "Mercamadrid"
          },
          "reference": {
            "type": "string",
            "description": "Provider's internal reference for this consumable",
            "example": "MM-TOM-1KG"
          }
        }
      },
      "supply-chain.Unit": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount of the consumable per unit",
            "example": 1000
          },
          "measure": {
            "type": "string",
            "description": "Measure of quantity (e.g. grs, ml, unt)",
            "example": "grs"
          }
        },
        "required": [
          "amount",
          "measure"
        ]
      },
      "supply-chain.Allergen": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the allergen",
            "example": "Gluten"
          }
        },
        "required": [
          "name"
        ]
      },
      "supply-chain.Consumable": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the consumable",
            "example": "Tomato"
          },
          "image": {
            "type": "string",
            "description": "Image URL for the consumable",
            "example": "https://cdn.platomico.com/consumables/tomato.jpg"
          },
          "trace": {
            "description": "Traceability information",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.Trace"
              }
            ]
          },
          "provider": {
            "description": "Default provider information",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.Provider"
              }
            ]
          },
          "providers": {
            "description": "Alternative provider ids for this consumable",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3",
              "64f1b8a2c3d4e5f6a7b8c9d4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unit": {
            "description": "Unit details of the consumable",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.Unit"
              }
            ]
          },
          "price": {
            "description": "Pricing details of the consumable",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.Price"
              }
            ]
          },
          "knownAs": {
            "description": "Other known names of the consumable",
            "example": [
              "Tomate",
              "Tomate rama"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "allergens": {
            "description": "Allergens of the consumable",
            "example": [
              {
                "name": "Gluten"
              }
            ],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/supply-chain.Allergen"
            }
          },
          "tags": {
            "description": "Tags associated with the consumable",
            "example": [
              "vegetable",
              "fresh"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "trace",
          "unit",
          "tags"
        ]
      },
      "supply-chain.CreateLocale": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Type of entity the locale translates (e.g. ITEM, MEAL, MENU, SECTION)",
            "example": "ITEM"
          },
          "locales": {
            "type": "object",
            "description": "Translations keyed by language code",
            "example": {
              "es": "Hamburguesa Clásica",
              "en": "Classic Burger",
              "fr": "Burger Classique"
            }
          },
          "trace": {
            "type": "object",
            "description": "Trace metadata (default language and source id the locale refers to)",
            "example": {
              "lang": "en",
              "sourceId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        },
        "required": [
          "type",
          "locales",
          "trace"
        ]
      },
      "supply-chain.BulkUpsertLocaleItem": {
        "type": "object",
        "properties": {
          "sourceId": {
            "type": "string",
            "description": "Id of the source entity the locale translates (e.g. the menu id)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "type": {
            "type": "string",
            "description": "Type of entity the locale translates (e.g. MENU, ITEM, MEAL)",
            "example": "MENU"
          },
          "lang": {
            "type": "string",
            "description": "Language code of this document (e.g. ES, EN, IT, DE)",
            "example": "IT"
          },
          "locales": {
            "type": "object",
            "description": "Translations keyed by entity key (item id, \"<itemId>.description\", meal id, ...). Merged into any existing document for the same source/type/lang.",
            "example": {
              "64f1b8a2c3d4e5f6a7b8c9d4": "Hamburger Classico",
              "64f1b8a2c3d4e5f6a7b8c9d4.description": "Con formaggio e bacon"
            }
          },
          "localeId": {
            "type": "string",
            "description": "Optional id of an existing locale document to update. When omitted, the document is matched by company + source + type + lang, and created if none exists.",
            "example": "64f1b8a2c3d4e5f6a7b8c9e0"
          }
        },
        "required": [
          "sourceId",
          "type",
          "lang",
          "locales"
        ]
      },
      "supply-chain.BulkUpsertLocales": {
        "type": "object",
        "properties": {
          "items": {
            "description": "The locale documents to create or update",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/supply-chain.BulkUpsertLocaleItem"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "supply-chain.UpdateLocale": {
        "type": "object",
        "properties": {
          "localeId": {
            "type": "string",
            "description": "Id of the locale document to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locales": {
            "type": "object",
            "description": "Translations keyed by language code",
            "example": {
              "es": "Hamburguesa Clásica",
              "en": "Classic Burger"
            }
          },
          "name": {
            "type": "string",
            "description": "Optional display name override for this locale",
            "example": "Classic Burger"
          }
        },
        "required": [
          "localeId",
          "locales"
        ]
      },
      "supply-chain.FetchByType": {
        "type": "object",
        "properties": {}
      },
      "supply-chain.CreateMenu": {
        "type": "object",
        "properties": {
          "locationsIds": {
            "description": "Location ids the menu is available at",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "description": "Source ids the menu is bound to (KIOSK, ORDERING, POS, etc.)",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "name": {
            "type": "string",
            "description": "Name of the menu",
            "example": "Lunch Menu"
          },
          "type": {
            "type": "string",
            "description": "Menu type (DEFAULT = per-item pricing, DAILY = flat price)",
            "enum": [
              "DEFAULT",
              "DAILY"
            ],
            "example": "DEFAULT"
          },
          "price": {
            "type": "object",
            "description": "Flat price when menu is of type DAILY",
            "example": {
              "amount": 1500,
              "currency": "EUR"
            }
          },
          "grid": {
            "description": "Grid layout cells (positioned items/sections)",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "listType": {
            "type": "string",
            "description": "List layout variant",
            "enum": [
              "ONE_COLUMN",
              "TWO_COLUMNS"
            ],
            "example": "TWO_COLUMNS"
          },
          "sections": {
            "description": "Menu sections, each listing items with optional overrides",
            "example": [
              {
                "name": "Starters",
                "collapsed": false,
                "image": "https://cdn.platomico.com/sections/starters.jpg",
                "items": [
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "visible": true,
                    "override": {
                      "name": "Special Starter",
                      "price": {
                        "amount": 550,
                        "currency": "EUR"
                      }
                    },
                    "commonModifiers": [
                      "64f1b8a2c3d4e5f6a7b8c9d5"
                    ]
                  }
                ]
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "upsells": {
            "type": "object",
            "description": "Meal-upsell forwarding shared across all layouts, keyed by item id. Omit a key -> legacy detection; \"NONE\" -> no upsell; <mealId> -> upsell to it.",
            "example": {
              "64f1b8a2c3d4e5f6a7b8c9d0": "64f1b8a2c3d4e5f6a7b8c9e2"
            }
          },
          "redirects": {
            "type": "object",
            "description": "Forced meal redirect, honored by the customer-facing clients only (kiosk and web), keyed by item id. Omit a key -> the product screen opens as usual; <mealId> -> selecting the item enters that meal directly with the item preselected as its first step.",
            "example": {
              "64f1b8a2c3d4e5f6a7b8c9d0": "64f1b8a2c3d4e5f6a7b8c9e2"
            }
          },
          "override": {
            "type": "object",
            "description": "Menu-level overrides keyed by product id. `price` is the price the sale is CHARGED at for this menu, replacing the catalog price of that item/meal. Distinct from the display-only sections[].items[].override.price.",
            "example": {
              "price": {
                "64f1b8a2c3d4e5f6a7b8c9d0": {
                  "amount": 950,
                  "currency": "EUR"
                }
              }
            }
          },
          "delivery": {
            "description": "Delivery aggregator menu (Glovo / Uber Eats / Just Eat). Single-column section list. Each item carries a platforms array ([\"*\"] = all aggregators).",
            "example": [
              {
                "name": "Burgers",
                "image": "https://cdn.platomico.com/sections/burgers.jpg",
                "items": [
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "visible": true,
                    "platforms": [
                      "*"
                    ],
                    "override": {
                      "price": {
                        "amount": 1100,
                        "currency": "EUR"
                      }
                    }
                  }
                ]
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "discounts": {
            "description": "Discount ids applied menu-wide",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d8"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "description": "Tags associated with the menu",
            "example": [
              "lunch",
              "weekdays"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "type",
          "sections",
          "discounts",
          "tags"
        ]
      },
      "supply-chain.UpdateMenu": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the menu to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "string",
            "description": "Name of the menu",
            "example": "Lunch Menu"
          },
          "type": {
            "type": "string",
            "description": "Menu type",
            "enum": [
              "DEFAULT",
              "DAILY"
            ],
            "example": "DEFAULT"
          },
          "price": {
            "type": "object",
            "description": "Flat price when menu is DAILY",
            "example": {
              "amount": 1500,
              "currency": "EUR"
            }
          },
          "grid": {
            "description": "Grid layout cells",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settings": {
            "type": "object",
            "description": "Menu presentation settings (theme + availability days)",
            "example": {
              "theme": {
                "color": "#222222",
                "backgroundColor": "#FFFFFF",
                "primaryFont": "Inter",
                "secondaryFont": "Roboto"
              },
              "days": [
                {
                  "active": true,
                  "from": "12:00",
                  "to": "16:00"
                },
                {
                  "active": true,
                  "from": "20:00",
                  "to": "23:30"
                }
              ]
            }
          },
          "sections": {
            "description": "Menu sections with their items",
            "example": [
              {
                "name": "Starters",
                "collapsed": false,
                "items": [
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "visible": true,
                    "commonModifiers": []
                  }
                ]
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "upsells": {
            "type": "object",
            "description": "Meal-upsell forwarding shared across all layouts, keyed by item id. Omit a key -> legacy detection; \"NONE\" -> no upsell; <mealId> -> upsell to it.",
            "example": {
              "64f1b8a2c3d4e5f6a7b8c9d0": "64f1b8a2c3d4e5f6a7b8c9e2"
            }
          },
          "redirects": {
            "type": "object",
            "description": "Forced meal redirect, honored by the customer-facing clients only (kiosk and web), keyed by item id. Omit a key -> the product screen opens as usual; <mealId> -> selecting the item enters that meal directly with the item preselected as its first step.",
            "example": {
              "64f1b8a2c3d4e5f6a7b8c9d0": "64f1b8a2c3d4e5f6a7b8c9e2"
            }
          },
          "override": {
            "type": "object",
            "description": "Menu-level overrides keyed by product id. `price` is the price the sale is CHARGED at for this menu, replacing the catalog price of that item/meal. Sent whole: an entry left out is removed. Distinct from the display-only sections[].items[].override.price.",
            "example": {
              "price": {
                "64f1b8a2c3d4e5f6a7b8c9d0": {
                  "amount": 950,
                  "currency": "EUR"
                }
              }
            }
          },
          "items": {
            "description": "Flat list of items with section assignment",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                "section": "Starters",
                "visible": true
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "delivery": {
            "description": "Delivery aggregator menu (Glovo / Uber Eats / Just Eat). Single-column section list. Each item carries a platforms array ([\"*\"] = all aggregators).",
            "example": [
              {
                "name": "Burgers",
                "items": [
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "visible": true,
                    "platforms": [
                      "*"
                    ]
                  }
                ]
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "draftSections": {
            "type": "object",
            "description": "Unpublished customer layout. Same shape as `sections`; promoted onto it by POST /menus/:id/publish. A PATCH carrying only draft* keys bumps no version and emits no REFRESH_MENUS, so the change stays off the devices."
          },
          "draftGrid": {
            "description": "Unpublished employee/POS grid. Promoted onto `grid`.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "draftDelivery": {
            "description": "Unpublished platforms layout. Promoted onto `delivery`, after which the Sinqro sync pushes it to the aggregators.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "draftMenuLevel": {
            "type": "object",
            "description": "Unpublished menu-wide maps (upsells, redirects, override). Promoted onto their live counterparts. Sent whole, like the live keys.",
            "example": {
              "upsells": {
                "64f1b8a2c3d4e5f6a7b8c9d0": "NONE"
              }
            }
          },
          "discounts": {
            "description": "Discount ids applied menu-wide",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d8"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "description": "Tags associated with the menu",
            "example": [
              "lunch"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "Other known names for the menu",
            "example": [
              "Mediodía"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "name",
          "type",
          "settings",
          "items",
          "tags",
          "knownAs"
        ]
      },
      "supply-chain.ObjectId": {
        "type": "object",
        "properties": {}
      },
      "supply-chain.Modifier": {
        "type": "object",
        "properties": {
          "id": {
            "description": "Modifier id (set by the server on creation)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.ObjectId"
              }
            ]
          },
          "companyId": {
            "type": "string",
            "description": "Company id (required for staff-created modifiers)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "name": {
            "type": "string",
            "description": "Name of the modifier",
            "example": "Extra cheese"
          },
          "description": {
            "type": "string",
            "description": "Description of the modifier",
            "example": "Add an extra slice of cheddar cheese"
          },
          "image": {
            "type": "string",
            "description": "Image of the modifier. Accepts a hosted URL (stored as-is) or a raw base64 payload (uploaded to S3 via common-service). Responses always carry the hosted URL.",
            "example": "https://cdn.platomico.com/modifiers/extra-cheese.png"
          },
          "trace": {
            "type": "object",
            "description": "Traceability information",
            "example": {
              "companyId": "64f1b8a2c3d4e5f6a7b8c9d1",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d2"
              ],
              "sku": "MOD-CHEESE",
              "bindingsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d3"
              ]
            }
          },
          "price": {
            "type": "object",
            "description": "Price of the modifier",
            "example": {
              "amount": 150,
              "currency": "EUR"
            }
          },
          "consumables": {
            "description": "Consumables (ingredients) used by this modifier",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d4",
                "amount": 30
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settings": {
            "type": "object",
            "description": "Presentation settings for the modifier",
            "example": {
              "color": "#FFFFFF",
              "backgroundColor": "#F39C12",
              "weight": "bold",
              "max": 3,
              "appearInSummary": true
            }
          },
          "tags": {
            "description": "Tags associated with the modifier",
            "example": [
              "cheese",
              "extras"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "Other known names of the modifier",
            "example": [
              "Extra queso"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "visible": {
            "type": "boolean",
            "description": "Record-level visibility. `false` hides the modifier from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible.",
            "example": true
          },
          "groups": {
            "description": "Optional group memberships. Each entry attaches the modifier to an existing group when `id` is provided, or finds-or-creates one by `name` (case-insensitive) otherwise. Pass `[]` to detach from every group.",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9e0"
              },
              {
                "name": "Toppings"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "description",
          "trace",
          "price",
          "consumables",
          "settings",
          "tags",
          "knownAs"
        ]
      },
      "supply-chain.UpdateModifier": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the modifier to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "trace": {
            "type": "object",
            "description": "Traceability fields to update",
            "example": {
              "sku": "MOD-CHEESE"
            }
          },
          "image": {
            "type": "string",
            "description": "Image of the modifier. Accepts a hosted URL (stored as-is) or a raw base64 payload (uploaded to S3 via common-service). Pass `null` to clear the stored photo; omit to keep it.",
            "nullable": true,
            "example": "https://cdn.platomico.com/modifiers/extra-cheese.png"
          },
          "price": {
            "type": "object",
            "description": "Price of the modifier",
            "example": {
              "amount": 150,
              "currency": "EUR"
            }
          },
          "consumables": {
            "description": "Consumables used by the modifier",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d4",
                "amount": 30
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settings": {
            "type": "object",
            "description": "Presentation settings",
            "example": {
              "color": "#FFFFFF",
              "appearInSummary": true
            }
          },
          "tags": {
            "description": "Tags associated with the modifier. Pass `[]` to clear them; omit to keep the stored value.",
            "example": [
              "cheese",
              "extras"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "trace",
          "price",
          "consumables",
          "settings"
        ]
      },
      "supply-chain.ModifierGroupTrace": {
        "type": "object",
        "properties": {
          "locationsIds": {
            "description": "Identifiers of the locations where the group is available",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "supply-chain.ModifierGroupLimits": {
        "type": "object",
        "properties": {
          "min": {
            "type": "number",
            "description": "Minimum units the customer must select. 0 makes the section optional.",
            "example": 1
          },
          "max": {
            "type": "number",
            "description": "Maximum units the customer may select. Counts units, not distinct options: three of the same option fill a max of 3.",
            "example": 2
          }
        },
        "required": [
          "min",
          "max"
        ]
      },
      "supply-chain.ModifierGroupSettings": {
        "type": "object",
        "properties": {
          "color": {
            "type": "string",
            "example": "#16a34a"
          },
          "backgroundColor": {
            "type": "string",
            "example": "#dcfce7"
          },
          "max": {
            "type": "number",
            "example": 3
          },
          "appearInSummary": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "supply-chain.ModifierGroup": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the modifier group",
            "example": "Toppings"
          },
          "description": {
            "type": "string",
            "description": "Description of the modifier group",
            "example": "Optional toppings for the pizza"
          },
          "trace": {
            "description": "Traceability information",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.ModifierGroupTrace"
              }
            ]
          },
          "modifiersIds": {
            "description": "Identifiers of modifiers that belong to the group",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "limits": {
            "description": "Selection bounds when the group is offered on a product. Absent keeps the group a plain label with no bounds (the legacy shape); present turns it into a bounded section.",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.ModifierGroupLimits"
              }
            ]
          },
          "repeatable": {
            "type": "boolean",
            "description": "Whether the same option may be taken more than once. Absent/false caps every pick at one unit; true defers the per-option cap to the modifier settings.max.",
            "example": false
          },
          "settings": {
            "description": "Presentation settings for the group",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.ModifierGroupSettings"
              }
            ]
          },
          "knownAs": {
            "description": "Other known names of the group",
            "example": [
              "Extras"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "description": "Tags associated with the group",
            "example": [
              "pizza",
              "extras"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "trace",
          "modifiersIds"
        ]
      },
      "supply-chain.UpdateModifierGroup": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the modifier group to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "string",
            "example": "Toppings"
          },
          "description": {
            "type": "string",
            "example": "Optional toppings"
          },
          "modifiersIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "limits": {
            "description": "Selection bounds. Pass `null` to turn the section back into a plain label; omit to keep the stored value.",
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.ModifierGroupLimits"
              }
            ]
          },
          "repeatable": {
            "type": "boolean",
            "example": false
          },
          "settings": {
            "type": "object"
          }
        },
        "required": [
          "id"
        ]
      },
      "supply-chain.CreateStockStore": {
        "type": "object",
        "properties": {
          "consumableId": {
            "type": "string",
            "description": "Consumable this stock entry tracks",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "amount": {
            "type": "number",
            "description": "Initial stored quantity",
            "example": 5000
          },
          "measure": {
            "type": "string",
            "description": "Unit of the stored quantity (e.g. grs, ml, unt)",
            "example": "grs"
          },
          "trace": {
            "type": "object",
            "description": "Trace metadata indicating which location the stock lives at",
            "example": {
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d1"
            }
          },
          "knownAs": {
            "description": "Other known names for the consumable at this location",
            "example": [
              "Tomate",
              "Tomate rama"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "consumableId",
          "amount",
          "measure",
          "trace"
        ]
      },
      "supply-chain.UpdateStockStore": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location being updated",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "stores": {
            "description": "Stock entries being set for the location",
            "example": [
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0",
                "amount": 5000,
                "measure": "grs"
              },
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d2",
                "amount": 500,
                "measure": "ml"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationId",
          "stores"
        ]
      },
      "supply-chain.PreparationTrace": {
        "type": "object",
        "properties": {
          "locationsIds": {
            "description": "Identifiers of the locations where the preparation is produced",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "supply-chain.PreparationIngredient": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Type of ingredient reference",
            "enum": [
              "INGREDIENT",
              "PREPARATION"
            ],
            "example": "INGREDIENT"
          },
          "id": {
            "type": "string",
            "description": "Identifier of the ingredient (consumable) or nested preparation",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "amount": {
            "type": "number",
            "description": "Amount of the ingredient used per batch",
            "example": 250
          },
          "measure": {
            "type": "string",
            "description": "Measure of the ingredient (e.g. grs, ml, unt)",
            "example": "grs"
          }
        },
        "required": [
          "id",
          "amount",
          "measure"
        ]
      },
      "supply-chain.Preparation": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the preparation",
            "example": "House Tomato Sauce"
          },
          "description": {
            "type": "string",
            "description": "Description of the preparation",
            "example": "Slow-cooked tomato sauce used in pastas and pizzas"
          },
          "trace": {
            "description": "Traceability information",
            "allOf": [
              {
                "$ref": "#/components/schemas/supply-chain.PreparationTrace"
              }
            ]
          },
          "ingredients": {
            "description": "List of ingredients (consumables or nested preparations)",
            "example": [
              {
                "type": "INGREDIENT",
                "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                "amount": 1000,
                "measure": "grs"
              },
              {
                "type": "INGREDIENT",
                "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                "amount": 50,
                "measure": "ml"
              }
            ],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/supply-chain.PreparationIngredient"
            }
          },
          "servingUnit": {
            "type": "string",
            "description": "Serving unit of the preparation (e.g. grs, ml, unt)",
            "example": "grs"
          },
          "tags": {
            "description": "Tags associated with the preparation",
            "example": [
              "sauce",
              "italian"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "Other known names of the preparation",
            "example": [
              "Salsa de tomate"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "trace",
          "ingredients",
          "tags"
        ]
      },
      "supply-chain.CreateOrder": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Company the order belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationId": {
            "type": "string",
            "description": "Location dispatching the delivery",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "orderId": {
            "type": "string",
            "description": "Platomico order id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d2"
          },
          "transactionId": {
            "type": "string",
            "description": "Transaction id associated with the delivery",
            "example": "64f1b8a2c3d4e5f6a7b8c9d3"
          }
        },
        "required": [
          "companyId",
          "locationId",
          "orderId"
        ]
      },
      "supply-chain.UpdateOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the purchase order to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationsIds": {
            "description": "Location ids the purchase order belongs to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string",
            "description": "New status for the purchase order",
            "enum": [
              "PENDING",
              "IN_PROGRESS",
              "RECEIVED",
              "CONFLICT",
              "BLOCKED",
              "CANCELED",
              "FAILED",
              "COMPLETED"
            ],
            "example": "RECEIVED"
          },
          "deliveryNoteId": {
            "type": "string",
            "description": "Delivery note id attached when the order was received",
            "example": "64f1b8a2c3d4e5f6a7b8c9d5"
          }
        },
        "required": [
          "id",
          "locationsIds",
          "status"
        ]
      },
      "supply-chain.CreateProvider": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Provider name",
            "example": "Mercamadrid"
          },
          "reference": {
            "type": "string",
            "description": "Provider's internal reference for accounting",
            "example": "MM-2026"
          },
          "email": {
            "type": "string",
            "description": "Contact email",
            "example": "orders@mercamadrid.com"
          },
          "phone": {
            "type": "string",
            "description": "Contact phone number",
            "example": "+34910001234"
          }
        },
        "required": [
          "name"
        ]
      },
      "supply-chain.UpdateProvider": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the provider to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "string",
            "description": "Provider name",
            "example": "Mercamadrid"
          },
          "reference": {
            "type": "string",
            "description": "Provider's internal reference for accounting",
            "example": "MM-2026"
          },
          "email": {
            "type": "string",
            "description": "Contact email",
            "example": "orders@mercamadrid.com"
          },
          "phone": {
            "type": "string",
            "description": "Contact phone number",
            "example": "+34910001234"
          }
        },
        "required": [
          "id"
        ]
      },
      "supply-chain.CreateMeasure": {
        "type": "object",
        "properties": {
          "image": {
            "type": "string",
            "description": "Image URL representing the packaging",
            "example": "https://cdn.platomico.com/measures/tomato-5kg.jpg"
          },
          "name": {
            "type": "string",
            "description": "Display name for the measure (packaging)",
            "example": "Caja 5kg tomate rama"
          },
          "amount": {
            "type": "number",
            "description": "Amount contained in one packaging unit",
            "example": 5000
          },
          "measure": {
            "type": "string",
            "description": "Measurement unit (e.g. grs, ml, unt)",
            "example": "grs"
          },
          "price": {
            "type": "object",
            "description": "Price per packaging unit (in currency minor unit / cents)",
            "example": {
              "amount": 1800,
              "currency": "EUR"
            }
          },
          "trace": {
            "type": "object",
            "description": "Traceability info linking the measure to provider, locations and consumable",
            "example": {
              "providerId": "64f1b8a2c3d4e5f6a7b8c9d3",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "reference": "MM-TOM-5KG",
              "consumableId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        },
        "required": [
          "image",
          "name",
          "amount",
          "measure",
          "price",
          "trace"
        ]
      },
      "supply-chain.UpdateMeasure": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the measure to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d9"
          },
          "image": {
            "type": "string",
            "description": "Image URL representing the packaging",
            "example": "https://cdn.platomico.com/measures/tomato-5kg.jpg"
          },
          "name": {
            "type": "string",
            "description": "Display name for the measure",
            "example": "Caja 5kg tomate rama"
          },
          "amount": {
            "type": "number",
            "description": "Amount contained in one packaging unit",
            "example": 5000
          },
          "measure": {
            "type": "string",
            "description": "Measurement unit (e.g. grs, ml, unt)",
            "example": "grs"
          },
          "price": {
            "type": "object",
            "description": "Price per packaging unit",
            "example": {
              "amount": 1800,
              "currency": "EUR"
            }
          },
          "consumables": {
            "description": "Consumable ids this measure is linked to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "trace": {
            "type": "object",
            "description": "Traceability info",
            "example": {
              "providerId": "64f1b8a2c3d4e5f6a7b8c9d3",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "reference": "MM-TOM-5KG"
            }
          }
        },
        "required": [
          "id",
          "image",
          "name",
          "amount",
          "measure",
          "price",
          "consumables",
          "trace"
        ]
      },
      "supply-chain.CreateMeal": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the meal (combo)",
            "example": "Burger Combo"
          },
          "description": {
            "type": "string",
            "description": "Description of the meal",
            "example": "Burger + fries + drink at a flat price"
          },
          "image": {
            "type": "string",
            "description": "Image URL of the meal",
            "example": "https://cdn.platomico.com/meals/burger-combo.jpg"
          },
          "trace": {
            "type": "object",
            "description": "Traceability information for the meal",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "sku": "COMBO-001"
            }
          },
          "price": {
            "type": "object",
            "description": "Base price for the meal (in currency minor unit / cents)",
            "example": {
              "amount": 1800,
              "currency": "EUR"
            }
          },
          "steps": {
            "description": "Steps composing the meal. Each step offers a set of items the customer can pick from, with quantity limits. A step with view MODIFIERS offers modifiers instead of items; its picks apply to the previously selected step item. For MODIFIERS steps limits.min/max bound the number of DISTINCT modifiers selected. A step copied from a master step (supply-chain/steps) carries its origin in stepId; absent on manual/legacy steps.",
            "example": [
              {
                "name": "Main",
                "items": [
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                    "price": {
                      "default": {
                        "amount": 0,
                        "currency": "EUR"
                      },
                      "extra": {
                        "amount": 200,
                        "currency": "EUR"
                      }
                    }
                  }
                ],
                "limits": {
                  "min": 1,
                  "free": 1,
                  "max": 1
                },
                "settings": {
                  "allowedToSkip": false
                }
              },
              {
                "name": "Sauces",
                "view": "MODIFIERS",
                "modifiers": [
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d2"
                  },
                  {
                    "id": "64f1b8a2c3d4e5f6a7b8c9d3",
                    "price": {
                      "default": {
                        "amount": 150,
                        "currency": "EUR"
                      }
                    },
                    "settings": {
                      "max": 3
                    }
                  }
                ],
                "limits": {
                  "min": 0,
                  "free": 0,
                  "max": 2
                },
                "settings": {
                  "allowedToSkip": true
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "taxes": {
            "description": "Tax ids applied to the meal",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "description": "Tags associated with the meal",
            "example": [
              "combo",
              "featured"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "Other known names of the meal",
            "example": [
              "Menu Burger",
              "Combo Hamburguesa"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "visible": {
            "type": "boolean",
            "description": "Record-level visibility. `false` hides the meal from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible.",
            "example": true
          }
        },
        "required": [
          "name",
          "trace",
          "price",
          "steps"
        ]
      },
      "supply-chain.UpdateMeal": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the meal to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "object",
            "description": "Name of the meal",
            "example": "Burger Combo"
          },
          "description": {
            "type": "object",
            "description": "Description of the meal",
            "example": "Burger + fries + drink at a flat price"
          },
          "image": {
            "type": "object",
            "description": "Image URL of the meal",
            "example": "https://cdn.platomico.com/meals/burger-combo.jpg"
          },
          "trace": {
            "type": "object",
            "description": "Traceability information",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ],
              "sku": "COMBO-001"
            }
          },
          "price": {
            "type": "object",
            "description": "Base price for the meal",
            "example": {
              "amount": 1800,
              "currency": "EUR"
            }
          },
          "steps": {
            "type": "object",
            "description": "Steps composing the meal"
          },
          "taxes": {
            "description": "Tax ids applied to the meal",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d4"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "description": "Tags associated with the meal",
            "example": [
              "combo",
              "featured"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "knownAs": {
            "description": "Other known names of the meal",
            "example": [
              "Menu Burger"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "visible": {
            "type": "object",
            "description": "Record-level visibility. `false` hides the meal from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible.",
            "example": true
          }
        },
        "required": [
          "id"
        ]
      },
      "supply-chain.CreateStep": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the master step (the step chip label)",
            "example": "Sauces"
          },
          "title": {
            "type": "string",
            "description": "Customer-facing title shown on the step context panel (meaningful for MODIFIERS steps)",
            "example": "Pick your sauces"
          },
          "description": {
            "type": "string",
            "description": "Customer-facing description for the step context panel",
            "example": "Up to 2 sauces included"
          },
          "trace": {
            "type": "object",
            "description": "Traceability information for the master step",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ]
            }
          },
          "view": {
            "type": "string",
            "description": "Which content the step offers. ITEMS (default when absent) or MODIFIERS.",
            "enum": [
              "ITEMS",
              "MODIFIERS"
            ],
            "example": "MODIFIERS"
          },
          "items": {
            "description": "Selectable items for ITEMS steps. Amounts arrive in currency major units and are stored in cents. Always persisted; [] for MODIFIERS steps.",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                "price": {
                  "default": {
                    "amount": 0,
                    "currency": "EUR"
                  },
                  "extra": {
                    "amount": 2,
                    "currency": "EUR"
                  }
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "modifiers": {
            "description": "Selectable modifiers for MODIFIERS steps. price/settings override the modifier catalog values; absent means catalog fallback.",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d2"
              },
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d3",
                "price": {
                  "default": {
                    "amount": 1.5,
                    "currency": "EUR"
                  }
                },
                "settings": {
                  "max": 3
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "limits": {
            "type": "object",
            "description": "Pick limits: min required, free included in the combo price, max cap. For MODIFIERS steps min/max bound DISTINCT modifiers.",
            "example": {
              "min": 0,
              "free": 0,
              "max": 2
            }
          },
          "settings": {
            "type": "object",
            "description": "Step settings (allowedToSkip = optional step)",
            "example": {
              "allowedToSkip": true
            }
          },
          "visible": {
            "type": "boolean",
            "description": "Record-level visibility. `false` hides the master step from the picker. Absent/`true` = visible.",
            "example": true
          }
        },
        "required": [
          "name",
          "trace",
          "limits",
          "settings"
        ]
      },
      "supply-chain.UpdateStep": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id of the master step to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "object",
            "description": "Name of the master step",
            "example": "Sauces"
          },
          "title": {
            "type": "object",
            "description": "Customer-facing title for the step context panel",
            "example": "Pick your sauces"
          },
          "description": {
            "type": "object",
            "description": "Customer-facing description for the step context panel",
            "example": "Up to 2 sauces included"
          },
          "trace": {
            "type": "object",
            "description": "Traceability information",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ]
            }
          },
          "view": {
            "type": "string",
            "description": "Which content the step offers",
            "enum": [
              "ITEMS",
              "MODIFIERS"
            ]
          },
          "items": {
            "type": "object",
            "description": "Selectable items for ITEMS steps"
          },
          "modifiers": {
            "type": "object",
            "description": "Selectable modifiers for MODIFIERS steps"
          },
          "limits": {
            "type": "object",
            "description": "Pick limits",
            "example": {
              "min": 0,
              "free": 0,
              "max": 2
            }
          },
          "settings": {
            "type": "object",
            "description": "Step settings",
            "example": {
              "allowedToSkip": true
            }
          },
          "visible": {
            "type": "object",
            "description": "Record-level visibility. `false` hides the master step from the picker.",
            "example": true
          }
        },
        "required": [
          "id"
        ]
      },
      "supply-chain.UploadDeliveryNodeFromDevice": {
        "type": "object",
        "properties": {
          "force": {
            "type": "boolean",
            "description": "If true, bypasses duplicate-detection on the delivery note and creates a new reception anyway.",
            "example": false
          },
          "images": {
            "description": "Images of the delivery note captured by the device",
            "example": [
              {
                "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
                "ext": "png"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "force",
          "images"
        ]
      },
      "supply-chain.UploadDeliveryNote": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location receiving the delivery",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "images": {
            "description": "Base64-encoded images of the delivery note",
            "example": [
              {
                "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
                "ext": "png"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationId",
          "images"
        ]
      },
      "supply-chain.AnalyzeDeliveryNote": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location where the delivery is being analyzed",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "images": {
            "description": "Base64-encoded delivery note images to OCR / analyze",
            "example": [
              {
                "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
                "ext": "png"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationId",
          "images"
        ]
      },
      "supply-chain.CreateReceptionV2": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Location where the reception took place",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "fileUrls": {
            "description": "URLs of the uploaded delivery note files",
            "example": [
              "https://cdn.platomico.com/delivery-notes/2026-04-23-mercamadrid.pdf"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "deliveryNoteId": {
            "type": "string",
            "description": "Delivery note id (from analyze step)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d5"
          },
          "provider": {
            "type": "object",
            "description": "Provider info. If id is omitted, a new provider is created with the given name.",
            "example": {
              "id": "64f1b8a2c3d4e5f6a7b8c9d3",
              "name": "Mercamadrid"
            }
          },
          "items": {
            "description": "Received items",
            "example": [
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d7",
                "measureId": "64f1b8a2c3d4e5f6a7b8c9d8",
                "quantity": 2,
                "measure": "unt",
                "price": {
                  "amount": 3600,
                  "currency": "EUR"
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationId",
          "fileUrls",
          "deliveryNoteId",
          "provider",
          "items"
        ]
      },
      "supply-chain.StaffConfirmReception": {
        "type": "object",
        "properties": {
          "receptionId": {
            "type": "string",
            "description": "Reception id to confirm",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "providerId": {
            "type": "string",
            "description": "Provider that delivered",
            "example": "64f1b8a2c3d4e5f6a7b8c9d3"
          },
          "locationId": {
            "type": "string",
            "description": "Location where the reception took place",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "consumables": {
            "description": "Consumables received with their packaging and price",
            "example": [
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d7",
                "measureId": "64f1b8a2c3d4e5f6a7b8c9d8",
                "amount": 5000,
                "price": {
                  "amount": 1800,
                  "currency": "EUR"
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "receptionId",
          "providerId",
          "locationId",
          "consumables"
        ]
      },
      "supply-chain.ConfirmReception": {
        "type": "object",
        "properties": {
          "receptionId": {
            "type": "string",
            "description": "Reception id to confirm",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "providerId": {
            "type": "string",
            "description": "Provider that delivered",
            "example": "64f1b8a2c3d4e5f6a7b8c9d3"
          },
          "consumables": {
            "description": "Consumables received with their packaging and price",
            "example": [
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d7",
                "measureId": "64f1b8a2c3d4e5f6a7b8c9d8",
                "amount": 5000,
                "price": {
                  "amount": 1800,
                  "currency": "EUR"
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "receptionId",
          "providerId",
          "consumables"
        ]
      },
      "supply-chain.UpdateReception": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Trace metadata linking the reception to its purchase order, member and location",
            "example": {
              "receptionId": "64f1b8a2c3d4e5f6a7b8c9d0",
              "purchaseOrderId": "64f1b8a2c3d4e5f6a7b8c9d4",
              "memberId": "64f1b8a2c3d4e5f6a7b8c9d6",
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d1"
            }
          },
          "consumables": {
            "description": "Received consumables with observed amounts and notes",
            "example": [
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d7",
                "packagingId": "64f1b8a2c3d4e5f6a7b8c9d8",
                "amount": 5000,
                "observation": "Two damaged boxes"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "trace",
          "consumables"
        ]
      },
      "supply-chain.FixReception": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Trace linking the reception to its delivery note, purchase order and location",
            "example": {
              "deliveryNoteId": "64f1b8a2c3d4e5f6a7b8c9d5",
              "receptionId": "64f1b8a2c3d4e5f6a7b8c9d0",
              "purchaseOrderId": "64f1b8a2c3d4e5f6a7b8c9d4",
              "locationId": "64f1b8a2c3d4e5f6a7b8c9d1"
            }
          },
          "ordered": {
            "description": "Items that were originally ordered",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d7",
                "name": "Tomato",
                "packaging": {
                  "id": "64f1b8a2c3d4e5f6a7b8c9d8",
                  "amount": 5000,
                  "name": "Box 5kg"
                },
                "price": {
                  "amount": 1800,
                  "currency": "EUR"
                }
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "received": {
            "description": "Items actually received (corrected values)",
            "example": [
              {
                "consumableId": "64f1b8a2c3d4e5f6a7b8c9d7",
                "packagingId": "64f1b8a2c3d4e5f6a7b8c9d8",
                "amount": 4500,
                "observation": "One 500g bag was missing"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "trace",
          "ordered",
          "received"
        ]
      },
      "supply-chain.CreateFeeRange": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Trace metadata indicating which locations the fee range applies to",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ]
            }
          },
          "min": {
            "type": "object",
            "description": "Minimum order amount for this fee tier (in cents)",
            "example": {
              "amount": 2000,
              "currency": "EUR"
            }
          },
          "type": {
            "type": "string",
            "description": "Type of fee",
            "enum": [
              "PERCENT"
            ],
            "example": "PERCENT"
          },
          "amount": {
            "type": "number",
            "description": "Fee amount (percent as integer, e.g. 10 for 10%)",
            "example": 10
          },
          "currency": {
            "type": "string",
            "description": "Currency code (ISO 4217)",
            "example": "EUR"
          }
        },
        "required": [
          "min",
          "type",
          "amount"
        ]
      },
      "supply-chain.UpdateFeeRange": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Fee range id to update",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "trace": {
            "type": "object",
            "description": "Trace metadata indicating which locations the fee range applies to",
            "example": {
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d1"
              ]
            }
          },
          "min": {
            "type": "object",
            "description": "Minimum order amount for this fee tier (in cents)",
            "example": {
              "amount": 2000,
              "currency": "EUR"
            }
          },
          "type": {
            "type": "string",
            "description": "Type of fee",
            "enum": [
              "PERCENT"
            ],
            "example": "PERCENT"
          },
          "amount": {
            "type": "number",
            "description": "Fee amount (percent as integer, e.g. 10 for 10%)",
            "example": 10
          },
          "currency": {
            "type": "string",
            "description": "Currency code (ISO 4217)",
            "example": "EUR"
          }
        },
        "required": [
          "id"
        ]
      },
      "supply-chain.UpdateVisibility": {
        "type": "object",
        "properties": {
          "resourceId": {
            "type": "string",
            "description": "Identifier of the item, meal or modifier to toggle",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "resourceType": {
            "type": "string",
            "description": "Kind of resource being toggled",
            "enum": [
              "ITEM",
              "MEAL",
              "MODIFIER"
            ],
            "example": "ITEM"
          },
          "locationIds": {
            "description": "Location ids the toggle applies to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "channel": {
            "type": "string",
            "description": "Channel the toggle applies to",
            "enum": [
              "WEB",
              "CUSTOMER",
              "EMPLOYEE",
              "DELIVERY"
            ],
            "example": "CUSTOMER"
          },
          "channels": {
            "type": "array",
            "description": "Optional: apply the toggle to several channels in one write, e.g. the POS selling something out everywhere at once. When present it REPLACES `channel`, and the record is still read and written once per location rather than once per channel.",
            "example": [
              "EMPLOYEE",
              "DELIVERY"
            ],
            "items": {
              "type": "string",
              "enum": [
                "WEB",
                "CUSTOMER",
                "EMPLOYEE",
                "DELIVERY"
              ]
            }
          },
          "hidden": {
            "type": "boolean",
            "description": "true hides the resource on this channel at those locations, false makes it visible again",
            "example": true
          },
          "until": {
            "type": "string",
            "description": "Optional deadline for a hide (\"snooze\"): an absolute ISO instant at which the resource becomes visible again on its own. Ignored when hidden is false, and dropped when it is not in the future. The caller computes it, so end-of-day means the end of the operator's day.",
            "example": "2026-07-29T21:59:59.999Z"
          }
        },
        "required": [
          "resourceId",
          "resourceType",
          "locationIds",
          "channel",
          "hidden"
        ]
      },
      "supply-chain.BulkVisibilityResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identifier of the item, meal or modifier",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "type": {
            "type": "string",
            "description": "Kind of resource",
            "enum": [
              "ITEM",
              "MEAL",
              "MODIFIER"
            ],
            "example": "ITEM"
          }
        },
        "required": [
          "id",
          "type"
        ]
      },
      "supply-chain.UpdateVisibilityBulk": {
        "type": "object",
        "properties": {
          "tags": {
            "description": "Tags whose members are toggled. Resolved server-side against the current catalog, so the caller cannot act on a stale list. A group toggle writes one record PER MEMBER: there is no tag-level state, so a product tagged afterwards is unaffected.",
            "example": [
              "Bebidas"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "resources": {
            "description": "Explicit resources to toggle, merged with whatever the tags resolve to",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/supply-chain.BulkVisibilityResource"
            }
          },
          "locationIds": {
            "description": "Location ids the toggle applies to",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "channel": {
            "type": "string",
            "description": "Channel the toggle applies to",
            "enum": [
              "WEB",
              "CUSTOMER",
              "EMPLOYEE",
              "DELIVERY"
            ],
            "example": "DELIVERY"
          },
          "channels": {
            "type": "array",
            "description": "Optional: apply the group toggle to several channels in one write. When present it REPLACES `channel`, and the whole group still ships as ONE atomic multi-path update.",
            "example": [
              "EMPLOYEE",
              "DELIVERY"
            ],
            "items": {
              "type": "string",
              "enum": [
                "WEB",
                "CUSTOMER",
                "EMPLOYEE",
                "DELIVERY"
              ]
            }
          },
          "hidden": {
            "type": "boolean",
            "description": "true hides every resolved resource on this channel at those locations, false makes them visible again",
            "example": true
          },
          "until": {
            "type": "string",
            "description": "Optional shared deadline for the whole group, as an absolute ISO instant",
            "example": "2026-07-29T21:59:59.999Z"
          }
        },
        "required": [
          "locationIds",
          "channel",
          "hidden"
        ]
      },
      "supply-chain.PublishVisibilityMenus": {
        "type": "object",
        "properties": {
          "locationIds": {
            "description": "Locations whose platform catalog is republished. A till sends its own location; the dashboard can send several.",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d1"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationIds"
        ]
      },
      "integrations.IntegrationPayload": {
        "type": "object",
        "properties": {
          "defaultId": {
            "type": "string",
            "description": "The id of the record",
            "example": "12321223"
          },
          "mealId": {
            "type": "string",
            "description": "The meal id of the record",
            "example": "2312312123"
          },
          "externalId": {
            "type": "string",
            "description": "The external id of the record",
            "example": "2312312123"
          },
          "defaultType": {
            "type": "string",
            "description": "The default type of the record",
            "example": "ITEM | MODIFIER | MEAL"
          },
          "externalType": {
            "type": "string",
            "description": "The external type of the record",
            "example": "ITEM | MODIFIER | MEAL"
          },
          "binding": {
            "type": "string",
            "description": "The binding of the Integration",
            "example": "LTR | RTL"
          },
          "locations": {
            "description": "The locations of the record",
            "example": [
              "123123123",
              "123123123"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "defaultId",
          "mealId",
          "externalId",
          "defaultType",
          "externalType",
          "binding",
          "locations"
        ]
      },
      "integrations.ItemPayload": {
        "type": "object",
        "properties": {
          "itemId": {
            "type": "string",
            "description": "The id of the item",
            "example": "12321223"
          },
          "externalItemId": {
            "type": "string",
            "description": "The external id of the item",
            "example": "2312312123"
          },
          "externalType": {
            "type": "string",
            "description": "The external type of the item",
            "example": "ITEM | MODIFIER | MEAL"
          },
          "binding": {
            "type": "string",
            "description": "The binding of the item",
            "example": "LTR | RTL"
          },
          "locations": {
            "description": "The locations of the item",
            "example": [
              "123123123",
              "123123123"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "itemId",
          "externalItemId",
          "externalType",
          "binding",
          "locations"
        ]
      },
      "integrations.ParserlocationPayload": {
        "type": "object",
        "properties": {
          "locations": {
            "description": "Array of locations",
            "example": [
              "location1",
              "location2"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locations"
        ]
      },
      "integrations.ParserDiscountsPayload": {
        "type": "object",
        "properties": {
          "discounts": {
            "description": "Array of discountss",
            "example": [
              "discounts1",
              "discounts2"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "discounts"
        ]
      },
      "integrations.ModifierPayload": {
        "type": "object",
        "properties": {
          "modifierId": {
            "type": "string",
            "description": "The id of the Modifier",
            "example": "12321223"
          },
          "externalModifierId": {
            "type": "string",
            "description": "The external id of the Modifier",
            "example": "2312312123"
          },
          "externalType": {
            "type": "string",
            "description": "The external type of the Modifier",
            "example": "Modifier | MODIFIER | MEAL"
          },
          "binding": {
            "type": "string",
            "description": "The binding of the Modifier",
            "example": "LTR | RTL"
          },
          "locations": {
            "description": "The locations of the Modifier",
            "example": [
              "123123123",
              "123123123"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "modifierId",
          "externalModifierId",
          "externalType",
          "binding",
          "locations"
        ]
      },
      "integrations.MealPayload": {
        "type": "object",
        "properties": {
          "mealId": {
            "type": "string",
            "description": "The id of the meal",
            "example": "12321223"
          },
          "externalMealId": {
            "type": "string",
            "description": "The external id of the meal",
            "example": "2312312123"
          },
          "externalType": {
            "type": "string",
            "description": "The external type of the meal",
            "example": "meal | MODIFIER | MEAL"
          },
          "binding": {
            "type": "string",
            "description": "The binding of the meal",
            "example": "LTR | RTL"
          },
          "locations": {
            "description": "The locations of the meal",
            "example": [
              "123123123",
              "123123123"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "mealId",
          "externalMealId",
          "externalType",
          "binding",
          "locations"
        ]
      },
      "integrations.DiscountPayload": {
        "type": "object",
        "properties": {
          "discountId": {
            "type": "string",
            "description": "The id of the discount",
            "example": "12321223"
          },
          "externaldiscountId": {
            "type": "string",
            "description": "The external id of the discount",
            "example": "2312312123"
          },
          "externalType": {
            "type": "string",
            "description": "The external type of the discount",
            "example": "discount | MODIFIER | MEAL"
          },
          "binding": {
            "type": "string",
            "description": "The binding of the discount",
            "example": "LTR | RTL"
          },
          "locations": {
            "description": "The locations of the discount",
            "example": [
              "123123123",
              "123123123"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "discountId",
          "externaldiscountId",
          "externalType",
          "binding",
          "locations"
        ]
      },
      "integrations.ParseSquareStrategy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platomico id (or external id, depending on direction) of the entity to resolve",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "type": {
            "type": "string",
            "description": "Entity kind",
            "enum": [
              "ITEM",
              "MEAL",
              "LOCATION"
            ],
            "example": "ITEM"
          },
          "modifiers": {
            "description": "Attached modifiers and their quantities",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d1",
                "quantity": 1
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "quantity": {
            "type": "number",
            "description": "Quantity of this item in the order",
            "example": 2
          },
          "steps": {
            "description": "Nested meal steps (2D array: steps → picks per step)",
            "example": [
              [
                {
                  "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                  "type": "ITEM",
                  "quantity": 1
                }
              ]
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "direction": {
            "type": "string",
            "description": "Direction of the parse. LTR = Platomico→Square, RTL = Square→Platomico.",
            "enum": [
              "LTR",
              "RTL"
            ],
            "example": "LTR"
          }
        },
        "required": [
          "id",
          "type",
          "companyId",
          "direction"
        ]
      },
      "integrations.CreateSquareOrder": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationId": {
            "type": "string",
            "description": "Square location id",
            "example": "L8H9K2MN5PQZX"
          },
          "source": {
            "type": "string",
            "description": "Order source (channel)",
            "example": "POS."
          },
          "name": {
            "type": "string",
            "description": "Order name / customer reference",
            "example": "Jane D."
          },
          "type": {
            "type": "string",
            "description": "Order type (e.g. DINE_IN, TAKEAWAY, DELIVERY)",
            "example": "TAKEAWAY"
          },
          "note": {
            "type": "string",
            "description": "Pre-composed kitchen-ticket note. Callers are expected to build the full note (source, customer, delivery, pickup time, comment); it is forwarded to Square verbatim and not re-composed here.",
            "example": "Sinqro\nTAKE_AWAY\nJane D.\nPickup: 23/04 19:30\nNo onions"
          },
          "pickup": {
            "type": "string",
            "description": "Pickup time (ISO 8601). When present the fulfillment is SCHEDULED.",
            "example": "2026-04-23T19:30:00.000Z"
          },
          "pickupType": {
            "type": "string",
            "description": "Source pickup type hint (e.g. 'SCHEDULED', 'ASAP'). Informational; the fulfillment schedule is driven by whether `pickup` is set.",
            "example": "SCHEDULED"
          },
          "metadata": {
            "type": "object",
            "description": "Arbitrary metadata forwarded to Square",
            "example": {
              "orderId": "ord_123"
            }
          },
          "discounts": {
            "description": "Order-level discounts",
            "example": [
              {
                "name": "10% off",
                "amount": 100,
                "currency": "EUR"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "order": {
            "description": "Order line items (with optional modifiers)",
            "example": [
              {
                "catalogObjectId": "sq_item_abc",
                "quantity": "2",
                "basePriceMoney": {
                  "amount": 500,
                  "currency": "EUR"
                },
                "modifiers": [
                  {
                    "catalogObjectId": "sq_mod_xyz",
                    "quantity": "1",
                    "basePriceMoney": {
                      "amount": 50,
                      "currency": "EUR"
                    }
                  }
                ]
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "companyId",
          "locationId",
          "source",
          "name",
          "type",
          "order"
        ]
      },
      "integrations.ReconcileSquareDto": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Ignored — the company is always resolved from the session token.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "date": {
            "type": "string",
            "description": "Single-day shortcut (ISO date). Use from/to for ranges.",
            "example": "2026-04-23"
          },
          "from": {
            "type": "string",
            "description": "Inclusive range start (ISO date)",
            "example": "2026-04-01"
          },
          "to": {
            "type": "string",
            "description": "Inclusive range end (ISO date)",
            "example": "2026-04-30"
          },
          "provider": {
            "type": "string",
            "description": "Optional provider filter (defaults to Square)",
            "example": "square"
          },
          "mode": {
            "type": "string",
            "description": "scan = report discrepancies only; fix = apply corrections",
            "enum": [
              "scan",
              "fix"
            ],
            "example": "scan"
          }
        }
      },
      "integrations.CreateSquareDeviceCode": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string",
            "description": "Platomico location id the terminal belongs to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "name": {
            "type": "string",
            "description": "Display name for the paired terminal",
            "example": "Front counter terminal"
          }
        },
        "required": [
          "locationId"
        ]
      },
      "integrations.ParseRevolutStrategy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platomico id (or external id, depending on direction) of the entity to resolve",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "type": {
            "type": "string",
            "description": "Entity kind",
            "enum": [
              "ITEM",
              "MEAL",
              "LOCATION"
            ],
            "example": "ITEM"
          },
          "modifiers": {
            "description": "Attached modifiers and their quantities",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d1",
                "quantity": 1
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "quantity": {
            "type": "number",
            "description": "Quantity of this item in the order",
            "example": 2
          },
          "steps": {
            "description": "Nested meal steps (2D array: steps → picks per step)",
            "example": [
              [
                {
                  "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                  "type": "ITEM",
                  "quantity": 1
                }
              ]
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "direction": {
            "type": "string",
            "description": "Direction of the parse. LTR = Platomico→Revolut, RTL = Revolut→Platomico.",
            "enum": [
              "LTR",
              "RTL"
            ],
            "example": "LTR"
          }
        },
        "required": [
          "id",
          "type",
          "companyId",
          "direction"
        ]
      },
      "integrations.ParseDefaultStrategy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platomico id (or external id, depending on direction) of the entity to resolve",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "type": {
            "type": "string",
            "description": "Entity kind",
            "enum": [
              "ITEM",
              "MEAL",
              "LOCATION"
            ],
            "example": "ITEM"
          },
          "modifiers": {
            "description": "Attached modifiers and their quantities",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d1",
                "quantity": 1
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "quantity": {
            "type": "number",
            "description": "Quantity of this item in the order",
            "example": 2
          },
          "steps": {
            "description": "Nested meal steps (2D array: steps → picks per step)",
            "example": [
              [
                {
                  "id": "64f1b8a2c3d4e5f6a7b8c9d2",
                  "type": "ITEM",
                  "quantity": 1
                }
              ]
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "direction": {
            "type": "string",
            "description": "Direction of the parse. LTR = Platomico→provider, RTL = provider→Platomico.",
            "enum": [
              "LTR",
              "RTL"
            ],
            "example": "LTR"
          }
        },
        "required": [
          "id",
          "type",
          "companyId",
          "direction"
        ]
      },
      "integrations.CreateContract": {
        "type": "object",
        "properties": {
          "trace": {
            "type": "object",
            "description": "Routing metadata: which provider this contract is for, which locations it covers, and the credentials bag",
            "example": {
              "provider": "stripe",
              "providerId": "pro_01H7A3B8K2MN5PQZX9YFVT",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ],
              "secrets": [
                {
                  "id": "api_key",
                  "provider": "stripe",
                  "value": "sk_live_..."
                }
              ]
            }
          },
          "settings": {
            "type": "object",
            "description": "Authorization mode used by the contract, plus optional event settings. For per-location providers (e.g. SINQRO) the transaction.created.sources allowlist doubles as the owned-sources registry the Square round-trip guard consults; omit it (or use [\"*\"]) to own every source.",
            "example": {
              "authorization": "SECRET",
              "events": {
                "transaction.created": {
                  "enabled": false,
                  "locationsIds": [
                    "*"
                  ],
                  "sources": [
                    "GLOVO"
                  ]
                }
              }
            }
          }
        },
        "required": [
          "trace",
          "settings"
        ]
      },
      "integrations.UpdateOperationsSettings": {
        "type": "object",
        "properties": {
          "print": {
            "type": "object",
            "description": "Toggle physical receipt printing for orders coming from this contract",
            "example": {
              "enabled": false
            }
          },
          "aiResolution": {
            "type": "object",
            "description": "Toggle AI item-matching for orders from this contract. When enabled, line items that don't resolve to a binding are matched by AI (high-confidence matches auto-applied). Opt-in: disabled unless set.",
            "example": {
              "enabled": true
            }
          },
          "deliveryParty": {
            "type": "string",
            "description": "Which party fulfils delivery for this contract's location. FIRST_PARTY means the selling point delivers itself (customer address must be collected); THIRD_PARTY means an aggregator/courier owns the delivery.",
            "enum": [
              "FIRST_PARTY",
              "THIRD_PARTY"
            ],
            "example": "FIRST_PARTY"
          }
        }
      },
      "integrations.SetContractActive": {
        "type": "object",
        "properties": {
          "active": {
            "type": "boolean",
            "description": "Enable (true) or disable (false) this contract. Disabling a loyalty (e.g. Comeback) contract makes the integration inert for its location without deleting the contract or its credentials.",
            "example": true
          }
        },
        "required": [
          "active"
        ]
      },
      "integrations.CreateProvider": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable provider name",
            "example": "Stripe"
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: provider slug, parser strategy, and companies it is scoped to (empty = global)",
            "example": {
              "provider": "stripe",
              "strategy": "DEFAULT",
              "companiesIds": [
                "64f1b8a2c3d4e5f6a7b8c9d0"
              ]
            }
          },
          "settings": {
            "type": "object",
            "description": "Provider configuration (authorization mode, required env vars / resources, rate limit)",
            "example": {
              "description": "Payment processing",
              "avatar": "https://cdn.platomico.com/providers/stripe.png",
              "authorization": "SECRET",
              "envs": [
                "STRIPE_API_KEY"
              ],
              "resources": [
                "payments",
                "payouts"
              ],
              "url": "https://stripe.com",
              "rateLimit": 100
            }
          },
          "active": {
            "type": "boolean",
            "description": "Whether the provider is available to companies",
            "example": true
          },
          "visible": {
            "type": "boolean",
            "description": "Whether the provider shows up in the integrations UI",
            "example": true
          }
        },
        "required": [
          "name",
          "trace"
        ]
      },
      "integrations.CreateBundleBinding": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "mealIdentifier": {
            "type": "string",
            "description": "Platomico meal id (the parent MEAL)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "stepItemIdentifier": {
            "type": "string",
            "description": "Platomico item id of the step pick that, combined with the meal, maps to the Square ITEM",
            "example": "64f1b8a2c3d4e5f6a7b8c9d2"
          },
          "squareItemIdentifier": {
            "type": "string",
            "description": "Square catalog object id of the target ITEM",
            "example": "A2C4E6G8I0K2M4O6Q8"
          },
          "mealName": {
            "type": "string",
            "description": "Display name of the meal (used in the bindings table)",
            "example": "las patatas"
          },
          "stepItemName": {
            "type": "string",
            "description": "Display name of the step item (used in the bindings table)",
            "example": "patatas fritas smoky"
          },
          "squareItemName": {
            "type": "string",
            "description": "Display name of the Square ITEM (used in the bindings table)",
            "example": "Patatas Fritas Smoky"
          }
        },
        "required": [
          "companyId",
          "mealIdentifier",
          "stepItemIdentifier",
          "squareItemIdentifier"
        ]
      },
      "integrations.ToggleEventSubscriptionBody": {
        "type": "object",
        "properties": {}
      },
      "integrations.ReceiveDeliverectOrderDto": {
        "type": "object",
        "properties": {}
      },
      "integrations.CreateWebhook": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Label shown in the dashboard",
            "example": "Accounting sync"
          },
          "url": {
            "type": "string",
            "description": "HTTPS endpoint that receives the POST",
            "example": "https://example.com/platomico/webhook"
          },
          "events": {
            "description": "Event types to deliver. Any of transaction.created, transaction.refunded, order.updated.",
            "example": [
              "transaction.created",
              "transaction.refunded"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locationsIds": {
            "description": "Locations whose events are delivered. Empty or omitted means every location.",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "url",
          "events"
        ]
      },
      "integrations.UpdateWebhook": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Accounting sync"
          },
          "url": {
            "type": "string",
            "example": "https://example.com/platomico/webhook"
          },
          "events": {
            "example": [
              "transaction.created"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locationsIds": {
            "description": "Empty means every location.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean",
            "description": "Pause (false) or resume (true) deliveries."
          }
        }
      },
      "integrations.LoyaltyCartLineDto": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitAmount": {
            "type": "number"
          }
        },
        "required": [
          "reference",
          "name",
          "quantity",
          "unitAmount"
        ]
      },
      "integrations.CheckoutResolveRequestDto": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string"
          },
          "identifier": {
            "type": "string",
            "description": "Customer lookup value: phone number, email, Comeback customer id, or scanned pass/QR code."
          },
          "phoneNumber": {
            "type": "string",
            "deprecated": true
          },
          "cart": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/integrations.LoyaltyCartLineDto"
            }
          }
        },
        "required": [
          "locationId",
          "identifier"
        ]
      },
      "integrations.LoyaltyOrderProductDto": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitAmount": {
            "type": "number"
          }
        },
        "required": [
          "reference",
          "name",
          "quantity",
          "unitAmount"
        ]
      },
      "integrations.SyncLoyaltyOrderRequestDto": {
        "type": "object",
        "properties": {
          "locationId": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "totalAmount": {
            "type": "number"
          },
          "discountAmount": {
            "type": "number"
          },
          "products": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/integrations.LoyaltyOrderProductDto"
            }
          },
          "appliedPromotionIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "locationId",
          "customerId",
          "externalId",
          "totalAmount",
          "discountAmount",
          "products",
          "appliedPromotionIds"
        ]
      },
      "integrations.UpdateLoyaltyReward": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "What the till prints on the ticket when the reward is taken",
            "example": "Un artículo seleccionado gratis"
          },
          "points": {
            "type": "number",
            "description": "What the reward costs the customer, in points",
            "example": 10000
          },
          "eligibleItemIdentifiers": {
            "description": "The meals the reward can be taken on. MEAL ids, checked against the company menu — an id that is not a meal of this company is rejected.",
            "example": [
              "6a4dbc6949036a84d355e506"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "eligibleQuantity": {
            "type": "number",
            "description": "How many of an eligible meal the reward covers",
            "example": 1
          }
        },
        "required": [
          "name",
          "points",
          "eligibleItemIdentifiers",
          "eligibleQuantity"
        ]
      },
      "integrations.UpdateLoyaltySettings": {
        "type": "object",
        "properties": {
          "pointsPerUnit": {
            "type": "number",
            "description": "Points earned per whole currency unit charged, floored. 100 means a 8,00 € sale earns 800 points.",
            "example": 100
          },
          "reward": {
            "description": "The reward on offer. Sent whole — a partial reward is not a reward.",
            "allOf": [
              {
                "$ref": "#/components/schemas/integrations.UpdateLoyaltyReward"
              }
            ]
          }
        }
      },
      "common.CreateFile": {
        "type": "object",
        "properties": {
          "base64": {
            "type": "string",
            "description": "Base64-encoded file content (no data: prefix)",
            "example": "iVBORw0KGgoAAAANSUhEUgAA..."
          },
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "locationId": {
            "type": "string",
            "description": "Optional owner location id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "ext": {
            "type": "string",
            "description": "File extension (without dot)",
            "example": "png"
          },
          "acl": {
            "type": "string",
            "description": "S3 ACL. Use \"public-read\" for publicly served assets, empty for private.",
            "enum": [
              "public-read",
              ""
            ],
            "example": "public-read"
          },
          "path": {
            "type": "string",
            "description": "Destination path/prefix within the bucket",
            "example": "receipts/2026-04"
          },
          "contentType": {
            "type": "string",
            "description": "MIME type",
            "example": "image/png"
          },
          "removeBackground": {
            "type": "boolean",
            "description": "When true, the image's background is removed via Pixelcut before storing (images only). The stored asset becomes a transparent PNG.",
            "example": false
          }
        },
        "required": [
          "base64",
          "companyId"
        ]
      },
      "common.SearchRecords": {
        "type": "object",
        "properties": {
          "directory": {
            "type": "string",
            "description": "Directory / path prefix to search under",
            "example": "receipts/2026-04"
          },
          "companyId": {
            "type": "string",
            "description": "Owner company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "ext": {
            "type": "string",
            "description": "Restrict to files with this extension",
            "example": "png"
          }
        },
        "required": [
          "directory",
          "companyId",
          "ext"
        ]
      },
      "common.InternalNotification": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Recipient email",
            "example": "user@platomico.com"
          },
          "template": {
            "type": "string",
            "description": "Template id/name to render",
            "example": "INTERNAL_WEEKLY_DIGEST"
          },
          "mailArgs": {
            "type": "object",
            "description": "Arguments injected into the email template",
            "example": {
              "firstName": "Jane",
              "total": 1250
            }
          },
          "attachments": {
            "description": "Attachments to include in the email",
            "example": [
              {
                "filename": "report.pdf",
                "path": "/tmp/report.pdf"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "email",
          "template"
        ]
      },
      "common.SendInvoiceEmailPayload": {
        "type": "object",
        "properties": {}
      },
      "common.ExportInvoicesByEmailPayload": {
        "type": "object",
        "properties": {}
      },
      "common.NotificationsPayload": {
        "type": "object",
        "properties": {
          "channel": {
            "type": "string",
            "description": "Delivery channel",
            "enum": [
              "EMAIL",
              "SMS",
              "PUSH",
              "TICKET"
            ],
            "example": "EMAIL"
          },
          "userType": {
            "type": "string",
            "description": "Recipient user type",
            "enum": [
              "USER",
              "CUSTOMERS",
              "MEMBERS",
              "PROVIDERS"
            ],
            "example": "MEMBERS"
          },
          "isRequired": {
            "type": "boolean",
            "description": "If true, the user cannot opt out of this notification",
            "example": false
          },
          "userId": {
            "type": "string",
            "description": "Recipient user id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          }
        },
        "required": [
          "channel",
          "userType",
          "isRequired",
          "userId"
        ]
      },
      "common.NotificationTemplatePayload": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Template name",
            "example": "Order Ready for Pickup"
          },
          "description": {
            "type": "string",
            "description": "Short description shown in the template picker",
            "example": "Sent when a takeaway order is ready."
          },
          "type": {
            "type": "string",
            "description": "Channel this template is rendered for",
            "enum": [
              "EMAIL",
              "SMS",
              "PUSH",
              "TICKET"
            ],
            "example": "EMAIL"
          },
          "subject": {
            "type": "string",
            "description": "Email subject (or SMS first line)",
            "example": "Your order is ready!"
          },
          "previewText": {
            "type": "string",
            "description": "Preview text shown in the inbox",
            "example": "Come pick it up within 15 minutes."
          },
          "url": {
            "type": "string",
            "description": "URL of the template source (MJML/HTML/text)",
            "example": "https://cdn.platomico.com/templates/order-ready.mjml"
          },
          "lang": {
            "type": "string",
            "description": "Language code",
            "example": "en"
          },
          "locationsIds": {
            "description": "Locations this template is enabled for",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "description",
          "type",
          "subject",
          "previewText",
          "url",
          "lang",
          "locationsIds"
        ]
      },
      "common.SmsPayload": {
        "type": "object",
        "properties": {}
      },
      "common.SmsMessagePayload": {
        "type": "object",
        "properties": {}
      },
      "common.CreateQrDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Destination URL the QR encodes",
            "example": "https://order.platomico.com/t/abc123"
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: owner company",
            "example": {
              "companyId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        },
        "required": [
          "url",
          "trace"
        ]
      },
      "common.UrlList": {
        "type": "object",
        "properties": {}
      },
      "common.Menu": {
        "type": "object",
        "properties": {}
      },
      "common.CreateForm": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Form name",
            "example": "Incident Report"
          },
          "receivers": {
            "description": "User ids that will receive submissions",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d0"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "locationId": {
            "type": "string",
            "description": "Scope the form to a location",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          }
        },
        "required": [
          "name",
          "receivers"
        ]
      },
      "common.SubmitForm": {
        "type": "object",
        "properties": {
          "form": {
            "type": "string",
            "description": "Form id to submit to",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "inputs": {
            "description": "Answered fields. TEXT values contain the typed string; FILE values contain the uploaded file URL.",
            "example": [
              {
                "label": "Customer name",
                "value": "Jane Doe",
                "type": "TEXT"
              },
              {
                "label": "Photo",
                "value": "https://cdn.platomico.com/f/abc.jpg",
                "type": "FILE"
              }
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "form",
          "inputs"
        ]
      },
      "common.Logs": {
        "type": "object",
        "properties": {
          "level": {
            "type": "string",
            "description": "Log severity",
            "enum": [
              "info",
              "warn",
              "error",
              "debug",
              "critical"
            ],
            "example": "info"
          },
          "service": {
            "type": "string",
            "description": "Originating service",
            "enum": [
              "auth",
              "common",
              "context",
              "integration",
              "listener",
              "operations",
              "payments",
              "supply-chain",
              "render"
            ],
            "example": "operations"
          },
          "module": {
            "type": "string",
            "description": "Originating module within the service",
            "enum": [
              "subscribers",
              "transactions"
            ],
            "example": "transactions"
          },
          "message": {
            "type": "string",
            "description": "Human-readable message",
            "example": "Charged subscription for company 64f1…"
          },
          "environment": {
            "type": "string",
            "description": "Environment name",
            "example": "production"
          },
          "metadata": {
            "type": "object",
            "description": "Free-form structured metadata to attach to the log entry",
            "example": {
              "orderId": "ord_123",
              "total": 1250
            }
          },
          "trace": {
            "type": "object",
            "description": "Correlation trace linking the log to a request, user and scope",
            "example": {
              "userId": "64f1b8a2c3d4e5f6a7b8c9d1",
              "requestId": "req_01H7A3B8K2MN5PQZX9YFVT",
              "companyId": "64f1b8a2c3d4e5f6a7b8c9d2",
              "locationsIds": [
                "64f1b8a2c3d4e5f6a7b8c9d3"
              ]
            }
          }
        },
        "required": [
          "level",
          "service",
          "message",
          "environment",
          "trace"
        ]
      },
      "common.FetchPayload": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Specific log entry id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "level": {
            "type": "string",
            "description": "Filter by log level",
            "enum": [
              "info",
              "warn",
              "error",
              "debug",
              "critical"
            ],
            "example": "error"
          },
          "service": {
            "type": "string",
            "description": "Filter by originating service",
            "example": "operations"
          },
          "environment": {
            "type": "string",
            "description": "Filter by environment",
            "enum": [
              "development",
              "production",
              "local"
            ],
            "example": "production"
          },
          "userId": {
            "type": "string",
            "description": "Filter by user id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "requestId": {
            "type": "string",
            "description": "Filter by request correlation id",
            "example": "req_01H7A3B8K2MN5PQZX9YFVT"
          },
          "companyId": {
            "type": "string",
            "description": "Filter by company id",
            "example": "64f1b8a2c3d4e5f6a7b8c9d2"
          },
          "locationsIds": {
            "description": "Filter by location ids",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "startDate": {
            "format": "date-time",
            "type": "string",
            "description": "Inclusive start of the time window",
            "example": "2026-04-01T00:00:00.000Z"
          },
          "endDate": {
            "format": "date-time",
            "type": "string",
            "description": "Exclusive end of the time window",
            "example": "2026-04-23T00:00:00.000Z"
          }
        }
      },
      "common.RecordDashboardAction": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "description": "One of the actions the BFF may record: the dashboard.* entries, plus the sign-in and sign-out it witnesses",
            "enum": [
              "users.user.invite",
              "users.user.update",
              "users.user.delete",
              "users.user.activate",
              "users.user.role-update",
              "users.user.password-update",
              "users.role.create",
              "users.role.update",
              "users.role.delete",
              "users.role.assign",
              "auth.api-key.create",
              "auth.api-key.revoke",
              "companies.company.update",
              "companies.company.billing-update",
              "locations.location.create",
              "locations.location.update",
              "locations.location.delete",
              "locations.location.status-update",
              "settings.setting.create",
              "settings.setting.update",
              "settings.setting.delete",
              "devices.device.create",
              "devices.device.update",
              "devices.device.delete",
              "endpoints.endpoint.create",
              "endpoints.endpoint.update",
              "endpoints.endpoint.delete",
              "schedules.schedule.update",
              "shifts.shift.create",
              "shifts.shift.update",
              "shifts.shift.delete",
              "orders.order.cancel",
              "orders.order.reassign",
              "payments.payment.refund",
              "payments.cash-drawer.adjust",
              "catalogue.product.create",
              "catalogue.product.update",
              "catalogue.product.delete",
              "catalogue.menu.create",
              "catalogue.menu.update",
              "catalogue.menu.delete",
              "catalogue.menu.publish",
              "catalogue.menu.discard",
              "catalogue.item.create",
              "catalogue.item.update",
              "catalogue.item.delete",
              "catalogue.meal.create",
              "catalogue.meal.update",
              "catalogue.meal.delete",
              "catalogue.modifier.create",
              "catalogue.modifier.update",
              "catalogue.modifier.delete",
              "catalogue.preparation.create",
              "catalogue.preparation.update",
              "catalogue.preparation.delete",
              "catalogue.step.create",
              "catalogue.step.update",
              "catalogue.step.delete",
              "catalogue.step.propagate",
              "catalogue.locale.create",
              "catalogue.locale.update",
              "catalogue.locale.bulk-upsert",
              "catalogue.visibility.update",
              "catalogue.visibility.bulk-update",
              "catalogue.visibility.publish",
              "supply.consumable.create",
              "supply.consumable.update",
              "supply.consumable.delete",
              "supply.provider.create",
              "supply.provider.update",
              "supply.provider.delete",
              "supply.measure.create",
              "supply.measure.update",
              "supply.measure.delete",
              "supply.purchase-order.create",
              "supply.purchase-order.update",
              "supply.purchase-order.delete",
              "supply.reception.create",
              "supply.reception.update",
              "supply.reception.delete",
              "supply.reception.confirm",
              "supply.reception.fix",
              "supply.reception.upload-delivery-note",
              "supply.stock-store.create",
              "supply.stock-store.update",
              "supply.stock-store.delete",
              "supply.consumption.track",
              "supply.consumption.retrack",
              "delivery.fee.create",
              "delivery.fee.update",
              "delivery.fee.delete",
              "delivery.order.create",
              "payments.discount.create",
              "payments.discount.update",
              "payments.discount.delete",
              "payments.fee.create",
              "payments.fee.update",
              "payments.tax.create",
              "payments.tax.update",
              "payments.flow.create",
              "payments.flow.update",
              "payments.flow.delete",
              "payments.table.create",
              "payments.table.update",
              "payments.cash-register.create",
              "payments.cash-register.open",
              "payments.cash-register.close",
              "payments.cash-register.track",
              "payments.cash-snapshot.update",
              "payments.cash-snapshot.fix",
              "payments.source.create",
              "marketing.subscriber.create",
              "payments.transaction.fix",
              "payments.platform.link-location",
              "payments.platform.link-domain",
              "payments.platform.link-reader",
              "payments.platform.link-subscription-price",
              "payments.platform.link-webhook",
              "payments.apple-pay.register-domain",
              "schedules.schedule.create",
              "schedules.schedule.delete",
              "shifts.template.create",
              "shifts.template.update",
              "shifts.template.delete",
              "shifts.template.restore",
              "shifts.absence.create",
              "shifts.absence.update",
              "shifts.absence.delete",
              "shifts.override.create",
              "shifts.override.update",
              "shifts.override.delete",
              "shifts.request.decide",
              "members.member.create",
              "members.member.update",
              "members.member.delete",
              "members.member.activate",
              "members.member.bulk-role-update",
              "loyalty.program.create",
              "loyalty.program.update",
              "loyalty.program.delete",
              "loyalty.reward.create",
              "loyalty.template.create",
              "loyalty.template.update",
              "loyalty.template.delete",
              "loyalty.color.create",
              "loyalty.benefit.create",
              "incidents.incident.create",
              "incidents.incident.update",
              "invoices.invoice.create",
              "delivery.fleet.update",
              "delivery.courier.invite",
              "delivery.courier.update",
              "delivery.courier.delete",
              "delivery.performance-threshold.update",
              "delivery.support-request.update",
              "orders.order.update",
              "releases.release.create",
              "stations.flow.upsert",
              "stations.flow.delete",
              "tasks.task.create",
              "tasks.task.update",
              "tasks.task.delete",
              "preferences.channel-groups.upsert",
              "onboarding.invite.seed",
              "integrations.integration.create",
              "integrations.binding.create",
              "integrations.binding.update",
              "integrations.binding.delete",
              "integrations.contract.create",
              "integrations.contract.update",
              "integrations.contract.activate",
              "integrations.provider.create",
              "integrations.event-subscription.toggle",
              "dashboard.page.view",
              "dashboard.resource.write",
              "dashboard.report.export",
              "dashboard.locations.select",
              "auth.session.sign-in",
              "auth.session.sign-in-failed",
              "auth.session.sign-out",
              "auth.session.company-switch",
              "auth.session.password-reset-request"
            ],
            "example": "dashboard.resource.write"
          },
          "result": {
            "type": "string",
            "enum": [
              "SUCCESS",
              "FAILURE",
              "DENIED"
            ],
            "example": "SUCCESS"
          },
          "resource": {
            "type": "string",
            "description": "The route or resource acted on",
            "example": "/api/operations/users"
          },
          "method": {
            "type": "string",
            "example": "PATCH"
          },
          "message": {
            "type": "string",
            "example": ""
          },
          "locationIds": {
            "description": "The locations the operator is working in — `['*']` for all of them. Each is checked against the session before it is stored; one the caller cannot reach is dropped, not rejected.",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "metadata": {
            "type": "object",
            "example": {
              "status": 200
            }
          }
        },
        "required": [
          "action",
          "result",
          "resource"
        ]
      },
      "common.AuditActor": {
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "description": "The user who acted",
            "example": "64f1b8a2c3d4e5f6a7b8c9d1"
          },
          "name": {
            "type": "string",
            "example": "Maria Gomez"
          },
          "email": {
            "type": "string",
            "example": "maria@platomico.com"
          },
          "role": {
            "type": "string",
            "example": "ADMIN"
          }
        },
        "required": [
          "userId",
          "name",
          "email",
          "role"
        ]
      },
      "common.AuditScope": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "example": "64f1b8a2c3d4e5f6a7b8c9d2"
          },
          "companyName": {
            "type": "string",
            "example": "Tacos Platomico"
          },
          "locationIds": {
            "description": "Every location in scope. `['*']` means all of them; an explicit list means those and no others.",
            "example": [
              "64f1b8a2c3d4e5f6a7b8c9d3"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "companyId",
          "companyName"
        ]
      },
      "common.AuditEntityReference": {
        "type": "object",
        "properties": {
          "identifier": {
            "type": "string",
            "example": "64f1b8a2c3d4e5f6a7b8c9e5"
          },
          "label": {
            "type": "string",
            "description": "Human-readable name of the affected record, denormalised",
            "example": "juan@tacosplatomico.com"
          }
        },
        "required": [
          "identifier",
          "label"
        ]
      },
      "common.AuditOrigin": {
        "type": "object",
        "properties": {
          "service": {
            "type": "string",
            "enum": [
              "authentication",
              "billing",
              "common",
              "integrations",
              "listener",
              "operations",
              "payments",
              "supply-chain"
            ],
            "example": "operations"
          },
          "module": {
            "type": "string",
            "example": "users"
          },
          "channel": {
            "type": "string",
            "enum": [
              "DASHBOARD",
              "API",
              "DEVICE",
              "INTERNAL",
              "SCHEDULED"
            ],
            "example": "DASHBOARD"
          },
          "method": {
            "type": "string",
            "example": "PATCH"
          },
          "path": {
            "type": "string",
            "example": "/operations/users"
          },
          "ipAddress": {
            "type": "string",
            "example": "81.61.20.4"
          },
          "userAgent": {
            "type": "string",
            "example": "Mozilla/5.0 …"
          },
          "requestIdentifier": {
            "type": "string",
            "description": "Correlates every record produced by one HTTP request",
            "example": "req_01H7A3B8K2MN5PQZX9YFVT"
          }
        },
        "required": [
          "service",
          "module",
          "channel",
          "method",
          "path",
          "ipAddress",
          "userAgent",
          "requestIdentifier"
        ]
      },
      "common.AuditChangeEntry": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "example": "role"
          },
          "from": {
            "type": "object",
            "example": "MANAGER"
          },
          "to": {
            "type": "object",
            "example": "ADMIN"
          }
        },
        "required": [
          "field",
          "from",
          "to"
        ]
      },
      "common.CreateAuditRecord": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "description": "Catalogued action. Rejected if absent from AUDIT_CATALOG",
            "enum": [
              "users.user.invite",
              "users.user.update",
              "users.user.delete",
              "users.user.activate",
              "users.user.role-update",
              "users.user.password-update",
              "users.role.create",
              "users.role.update",
              "users.role.delete",
              "users.role.assign",
              "auth.api-key.create",
              "auth.api-key.revoke",
              "companies.company.update",
              "companies.company.billing-update",
              "locations.location.create",
              "locations.location.update",
              "locations.location.delete",
              "locations.location.status-update",
              "settings.setting.create",
              "settings.setting.update",
              "settings.setting.delete",
              "devices.device.create",
              "devices.device.update",
              "devices.device.delete",
              "endpoints.endpoint.create",
              "endpoints.endpoint.update",
              "endpoints.endpoint.delete",
              "schedules.schedule.update",
              "shifts.shift.create",
              "shifts.shift.update",
              "shifts.shift.delete",
              "orders.order.cancel",
              "orders.order.reassign",
              "payments.payment.refund",
              "payments.cash-drawer.adjust",
              "catalogue.product.create",
              "catalogue.product.update",
              "catalogue.product.delete",
              "catalogue.menu.create",
              "catalogue.menu.update",
              "catalogue.menu.delete",
              "catalogue.menu.publish",
              "catalogue.menu.discard",
              "catalogue.item.create",
              "catalogue.item.update",
              "catalogue.item.delete",
              "catalogue.meal.create",
              "catalogue.meal.update",
              "catalogue.meal.delete",
              "catalogue.modifier.create",
              "catalogue.modifier.update",
              "catalogue.modifier.delete",
              "catalogue.preparation.create",
              "catalogue.preparation.update",
              "catalogue.preparation.delete",
              "catalogue.step.create",
              "catalogue.step.update",
              "catalogue.step.delete",
              "catalogue.step.propagate",
              "catalogue.locale.create",
              "catalogue.locale.update",
              "catalogue.locale.bulk-upsert",
              "catalogue.visibility.update",
              "catalogue.visibility.bulk-update",
              "catalogue.visibility.publish",
              "supply.consumable.create",
              "supply.consumable.update",
              "supply.consumable.delete",
              "supply.provider.create",
              "supply.provider.update",
              "supply.provider.delete",
              "supply.measure.create",
              "supply.measure.update",
              "supply.measure.delete",
              "supply.purchase-order.create",
              "supply.purchase-order.update",
              "supply.purchase-order.delete",
              "supply.reception.create",
              "supply.reception.update",
              "supply.reception.delete",
              "supply.reception.confirm",
              "supply.reception.fix",
              "supply.reception.upload-delivery-note",
              "supply.stock-store.create",
              "supply.stock-store.update",
              "supply.stock-store.delete",
              "supply.consumption.track",
              "supply.consumption.retrack",
              "delivery.fee.create",
              "delivery.fee.update",
              "delivery.fee.delete",
              "delivery.order.create",
              "payments.discount.create",
              "payments.discount.update",
              "payments.discount.delete",
              "payments.fee.create",
              "payments.fee.update",
              "payments.tax.create",
              "payments.tax.update",
              "payments.flow.create",
              "payments.flow.update",
              "payments.flow.delete",
              "payments.table.create",
              "payments.table.update",
              "payments.cash-register.create",
              "payments.cash-register.open",
              "payments.cash-register.close",
              "payments.cash-register.track",
              "payments.cash-snapshot.update",
              "payments.cash-snapshot.fix",
              "payments.source.create",
              "marketing.subscriber.create",
              "payments.transaction.fix",
              "payments.platform.link-location",
              "payments.platform.link-domain",
              "payments.platform.link-reader",
              "payments.platform.link-subscription-price",
              "payments.platform.link-webhook",
              "payments.apple-pay.register-domain",
              "schedules.schedule.create",
              "schedules.schedule.delete",
              "shifts.template.create",
              "shifts.template.update",
              "shifts.template.delete",
              "shifts.template.restore",
              "shifts.absence.create",
              "shifts.absence.update",
              "shifts.absence.delete",
              "shifts.override.create",
              "shifts.override.update",
              "shifts.override.delete",
              "shifts.request.decide",
              "members.member.create",
              "members.member.update",
              "members.member.delete",
              "members.member.activate",
              "members.member.bulk-role-update",
              "loyalty.program.create",
              "loyalty.program.update",
              "loyalty.program.delete",
              "loyalty.reward.create",
              "loyalty.template.create",
              "loyalty.template.update",
              "loyalty.template.delete",
              "loyalty.color.create",
              "loyalty.benefit.create",
              "incidents.incident.create",
              "incidents.incident.update",
              "invoices.invoice.create",
              "delivery.fleet.update",
              "delivery.courier.invite",
              "delivery.courier.update",
              "delivery.courier.delete",
              "delivery.performance-threshold.update",
              "delivery.support-request.update",
              "orders.order.update",
              "releases.release.create",
              "stations.flow.upsert",
              "stations.flow.delete",
              "tasks.task.create",
              "tasks.task.update",
              "tasks.task.delete",
              "preferences.channel-groups.upsert",
              "onboarding.invite.seed",
              "integrations.integration.create",
              "integrations.binding.create",
              "integrations.binding.update",
              "integrations.binding.delete",
              "integrations.contract.create",
              "integrations.contract.update",
              "integrations.contract.activate",
              "integrations.provider.create",
              "integrations.event-subscription.toggle",
              "dashboard.page.view",
              "dashboard.resource.write",
              "dashboard.report.export",
              "dashboard.locations.select",
              "auth.session.sign-in",
              "auth.session.sign-in-failed",
              "auth.session.sign-out",
              "auth.session.company-switch",
              "auth.session.password-reset-request"
            ],
            "example": "users.user.role-update"
          },
          "actorType": {
            "type": "string",
            "enum": [
              "USER",
              "MEMBER",
              "CUSTOMER",
              "DEVICE",
              "API",
              "STAFF",
              "ENDPOINT",
              "SYSTEM"
            ],
            "example": "USER"
          },
          "result": {
            "type": "string",
            "enum": [
              "SUCCESS",
              "FAILURE",
              "DENIED"
            ],
            "example": "SUCCESS"
          },
          "actor": {
            "$ref": "#/components/schemas/common.AuditActor"
          },
          "scope": {
            "$ref": "#/components/schemas/common.AuditScope"
          },
          "entity": {
            "$ref": "#/components/schemas/common.AuditEntityReference"
          },
          "origin": {
            "$ref": "#/components/schemas/common.AuditOrigin"
          },
          "message": {
            "type": "string",
            "description": "Rejection reason on FAILURE or DENIED, empty otherwise",
            "example": ""
          },
          "changes": {
            "description": "Before/after pairs. Empty when the action is not a change",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/common.AuditChangeEntry"
            }
          },
          "metadata": {
            "type": "object",
            "example": {
              "reason": "client no-show"
            }
          }
        },
        "required": [
          "action",
          "actorType",
          "result",
          "actor",
          "scope",
          "entity",
          "origin"
        ]
      },
      "common.FetchAuditRecords": {
        "type": "object",
        "properties": {
          "companyId": {
            "type": "string",
            "description": "Company scope. Forced to the caller company on the HTTP route; only the internal RPC may set it freely"
          },
          "locationId": {
            "type": "string",
            "description": "Filter by location"
          },
          "actorId": {
            "type": "string",
            "description": "Filter by the user who acted"
          },
          "actorType": {
            "type": "string",
            "enum": [
              "USER",
              "MEMBER",
              "CUSTOMER",
              "DEVICE",
              "API",
              "STAFF",
              "ENDPOINT",
              "SYSTEM"
            ]
          },
          "action": {
            "type": "string",
            "description": "Exact action, or a prefix such as `users.` to match a whole domain",
            "enum": [
              "users.user.invite",
              "users.user.update",
              "users.user.delete",
              "users.user.activate",
              "users.user.role-update",
              "users.user.password-update",
              "users.role.create",
              "users.role.update",
              "users.role.delete",
              "users.role.assign",
              "auth.api-key.create",
              "auth.api-key.revoke",
              "companies.company.update",
              "companies.company.billing-update",
              "locations.location.create",
              "locations.location.update",
              "locations.location.delete",
              "locations.location.status-update",
              "settings.setting.create",
              "settings.setting.update",
              "settings.setting.delete",
              "devices.device.create",
              "devices.device.update",
              "devices.device.delete",
              "endpoints.endpoint.create",
              "endpoints.endpoint.update",
              "endpoints.endpoint.delete",
              "schedules.schedule.update",
              "shifts.shift.create",
              "shifts.shift.update",
              "shifts.shift.delete",
              "orders.order.cancel",
              "orders.order.reassign",
              "payments.payment.refund",
              "payments.cash-drawer.adjust",
              "catalogue.product.create",
              "catalogue.product.update",
              "catalogue.product.delete",
              "catalogue.menu.create",
              "catalogue.menu.update",
              "catalogue.menu.delete",
              "catalogue.menu.publish",
              "catalogue.menu.discard",
              "catalogue.item.create",
              "catalogue.item.update",
              "catalogue.item.delete",
              "catalogue.meal.create",
              "catalogue.meal.update",
              "catalogue.meal.delete",
              "catalogue.modifier.create",
              "catalogue.modifier.update",
              "catalogue.modifier.delete",
              "catalogue.preparation.create",
              "catalogue.preparation.update",
              "catalogue.preparation.delete",
              "catalogue.step.create",
              "catalogue.step.update",
              "catalogue.step.delete",
              "catalogue.step.propagate",
              "catalogue.locale.create",
              "catalogue.locale.update",
              "catalogue.locale.bulk-upsert",
              "catalogue.visibility.update",
              "catalogue.visibility.bulk-update",
              "catalogue.visibility.publish",
              "supply.consumable.create",
              "supply.consumable.update",
              "supply.consumable.delete",
              "supply.provider.create",
              "supply.provider.update",
              "supply.provider.delete",
              "supply.measure.create",
              "supply.measure.update",
              "supply.measure.delete",
              "supply.purchase-order.create",
              "supply.purchase-order.update",
              "supply.purchase-order.delete",
              "supply.reception.create",
              "supply.reception.update",
              "supply.reception.delete",
              "supply.reception.confirm",
              "supply.reception.fix",
              "supply.reception.upload-delivery-note",
              "supply.stock-store.create",
              "supply.stock-store.update",
              "supply.stock-store.delete",
              "supply.consumption.track",
              "supply.consumption.retrack",
              "delivery.fee.create",
              "delivery.fee.update",
              "delivery.fee.delete",
              "delivery.order.create",
              "payments.discount.create",
              "payments.discount.update",
              "payments.discount.delete",
              "payments.fee.create",
              "payments.fee.update",
              "payments.tax.create",
              "payments.tax.update",
              "payments.flow.create",
              "payments.flow.update",
              "payments.flow.delete",
              "payments.table.create",
              "payments.table.update",
              "payments.cash-register.create",
              "payments.cash-register.open",
              "payments.cash-register.close",
              "payments.cash-register.track",
              "payments.cash-snapshot.update",
              "payments.cash-snapshot.fix",
              "payments.source.create",
              "marketing.subscriber.create",
              "payments.transaction.fix",
              "payments.platform.link-location",
              "payments.platform.link-domain",
              "payments.platform.link-reader",
              "payments.platform.link-subscription-price",
              "payments.platform.link-webhook",
              "payments.apple-pay.register-domain",
              "schedules.schedule.create",
              "schedules.schedule.delete",
              "shifts.template.create",
              "shifts.template.update",
              "shifts.template.delete",
              "shifts.template.restore",
              "shifts.absence.create",
              "shifts.absence.update",
              "shifts.absence.delete",
              "shifts.override.create",
              "shifts.override.update",
              "shifts.override.delete",
              "shifts.request.decide",
              "members.member.create",
              "members.member.update",
              "members.member.delete",
              "members.member.activate",
              "members.member.bulk-role-update",
              "loyalty.program.create",
              "loyalty.program.update",
              "loyalty.program.delete",
              "loyalty.reward.create",
              "loyalty.template.create",
              "loyalty.template.update",
              "loyalty.template.delete",
              "loyalty.color.create",
              "loyalty.benefit.create",
              "incidents.incident.create",
              "incidents.incident.update",
              "invoices.invoice.create",
              "delivery.fleet.update",
              "delivery.courier.invite",
              "delivery.courier.update",
              "delivery.courier.delete",
              "delivery.performance-threshold.update",
              "delivery.support-request.update",
              "orders.order.update",
              "releases.release.create",
              "stations.flow.upsert",
              "stations.flow.delete",
              "tasks.task.create",
              "tasks.task.update",
              "tasks.task.delete",
              "preferences.channel-groups.upsert",
              "onboarding.invite.seed",
              "integrations.integration.create",
              "integrations.binding.create",
              "integrations.binding.update",
              "integrations.binding.delete",
              "integrations.contract.create",
              "integrations.contract.update",
              "integrations.contract.activate",
              "integrations.provider.create",
              "integrations.event-subscription.toggle",
              "dashboard.page.view",
              "dashboard.resource.write",
              "dashboard.report.export",
              "dashboard.locations.select",
              "auth.session.sign-in",
              "auth.session.sign-in-failed",
              "auth.session.sign-out",
              "auth.session.company-switch",
              "auth.session.password-reset-request"
            ]
          },
          "entityType": {
            "type": "string",
            "enum": [
              "USER",
              "USER_ROLE",
              "API_KEY",
              "COMPANY",
              "LOCATION",
              "SETTING",
              "DEVICE",
              "ENDPOINT",
              "SCHEDULE",
              "SHIFT",
              "ORDER",
              "PAYMENT",
              "CASH_DRAWER",
              "PRODUCT",
              "SESSION",
              "PAGE",
              "RESOURCE",
              "REPORT",
              "MENU",
              "ITEM",
              "MEAL",
              "MODIFIER",
              "PREPARATION",
              "STEP",
              "LOCALE",
              "VISIBILITY",
              "CONSUMABLE",
              "PROVIDER",
              "MEASURE",
              "PURCHASE_ORDER",
              "RECEPTION",
              "STOCK_STORE",
              "CONSUMPTION",
              "DELIVERY_FEE",
              "DELIVERY_ORDER",
              "DISCOUNT",
              "FEE",
              "TAX",
              "PAYMENT_FLOW",
              "TABLE",
              "CASH_REGISTER",
              "CASH_SNAPSHOT",
              "PAYMENT_SOURCE",
              "SUBSCRIBER",
              "TRANSACTION",
              "PLATFORM_LINK",
              "APPLE_PAY_DOMAIN",
              "SHIFT_TEMPLATE",
              "SHIFT_ABSENCE",
              "SHIFT_OVERRIDE",
              "SHIFT_REQUEST",
              "MEMBER",
              "LOYALTY_PROGRAM",
              "LOYALTY_TEMPLATE",
              "LOYALTY_BENEFIT",
              "LOYALTY_REWARD",
              "LOYALTY_COLOR",
              "INCIDENT",
              "INVOICE",
              "DELIVERY_FLEET",
              "DELIVERY_COURIER",
              "SUPPORT_REQUEST",
              "PERFORMANCE_THRESHOLD",
              "APP_RELEASE",
              "STATIONS_FLOW",
              "TASK",
              "CHANNEL_GROUPS",
              "ONBOARDING_INVITE",
              "INTEGRATION",
              "INTEGRATION_BINDING",
              "INTEGRATION_CONTRACT",
              "INTEGRATION_PROVIDER",
              "EVENT_SUBSCRIPTION"
            ]
          },
          "entityIdentifier": {
            "type": "string",
            "description": "Filter by the affected record"
          },
          "result": {
            "type": "string",
            "enum": [
              "SUCCESS",
              "FAILURE",
              "DENIED"
            ]
          },
          "channel": {
            "type": "string",
            "enum": [
              "DASHBOARD",
              "API",
              "DEVICE",
              "INTERNAL",
              "SCHEDULED"
            ]
          },
          "startDate": {
            "type": "string",
            "example": "2026-08-01T00:00:00.000Z"
          },
          "endDate": {
            "type": "string",
            "example": "2026-08-25T23:59:59.999Z"
          },
          "skip": {
            "type": "number",
            "example": 0
          },
          "take": {
            "type": "number",
            "example": 50,
            "description": "Capped at 200"
          }
        }
      },
      "common.OnMessage": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "User message content to send to the AI",
            "example": "Summarize today’s sales and flag any outliers."
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: which model handles the request and which chat to append to",
            "example": {
              "modelId": "64f1b8a2c3d4e5f6a7b8c9d0",
              "chatId": "64f1b8a2c3d4e5f6a7b8c9d1"
            }
          }
        },
        "required": [
          "content",
          "trace"
        ]
      },
      "common.CreateBrain": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable brain name",
            "example": "Sales Analyst"
          },
          "description": {
            "type": "string",
            "description": "What the brain is for",
            "example": "Answers questions about sales and operations metrics."
          },
          "role": {
            "type": "string",
            "description": "System prompt / persona the brain adopts",
            "example": "You are a senior analyst. Be concise and quantitative."
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: which AI model backs this brain",
            "example": {
              "modelId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        },
        "required": [
          "name",
          "description",
          "role",
          "trace"
        ]
      },
      "common.CreateContext": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable context name",
            "example": "Refund policy"
          },
          "description": {
            "type": "string",
            "description": "Optional short description",
            "example": "Guidance for handling refund requests under 30 days."
          },
          "content": {
            "type": "object",
            "description": "Structured knowledge attached to the context",
            "example": {
              "title": "Refunds",
              "description": "How to refund a customer.",
              "cases": [
                "Wrong item delivered",
                "Item never arrived"
              ],
              "solutions": [
                "Refund via original payment method",
                "Offer replacement"
              ]
            }
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: which AI model this context belongs to",
            "example": {
              "modelId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        },
        "required": [
          "name",
          "content",
          "trace"
        ]
      },
      "common.CreateTool": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Tool name exposed to the AI",
            "example": "getSalesByDay"
          },
          "description": {
            "type": "string",
            "description": "What the tool does (the model reads this)",
            "example": "Returns gross sales grouped by day for a location."
          },
          "settings": {
            "type": "object",
            "description": "Backing configuration: which internal model owns it, which RPC to call, and input/output schemas",
            "example": {
              "model": "claude-sonnet-4-6",
              "rpc": "operations/analytics:sales-by-day",
              "input": {
                "type": "object",
                "properties": {
                  "locationId": {
                    "type": "string"
                  }
                }
              },
              "output": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "trace": {
            "type": "object",
            "description": "Routing metadata: which AI model this tool is attached to",
            "example": {
              "modelId": "64f1b8a2c3d4e5f6a7b8c9d0"
            }
          }
        },
        "required": [
          "name",
          "settings",
          "trace"
        ]
      },
      "common.CreateModel": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable model name",
            "example": "Customer Support Assistant"
          },
          "description": {
            "type": "string",
            "description": "Optional short description",
            "example": "Answers customer questions using the knowledge base."
          }
        },
        "required": [
          "name"
        ]
      },
      "common.TranslateLocaleEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable identifier for this string (preserved in the result)",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "text": {
            "type": "string",
            "description": "The source-language text to translate",
            "example": "Hamburguesa Clásica"
          }
        },
        "required": [
          "id",
          "text"
        ]
      },
      "common.TranslateLocalesPayload": {
        "type": "object",
        "properties": {
          "sourceLang": {
            "type": "string",
            "description": "Source language code (e.g. ES, EN)",
            "example": "ES"
          },
          "targetLang": {
            "type": "string",
            "description": "Target language code (e.g. IT, DE, JP, CH, AR)",
            "example": "IT"
          },
          "entries": {
            "description": "The strings to translate, each with a stable id",
            "example": [
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d0",
                "text": "Hamburguesa Clásica"
              },
              {
                "id": "64f1b8a2c3d4e5f6a7b8c9d1",
                "text": "Patatas Bravas"
              }
            ],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/common.TranslateLocaleEntry"
            }
          }
        },
        "required": [
          "sourceLang",
          "targetLang",
          "entries"
        ]
      },
      "common.MenuImportPayload": {
        "type": "object",
        "properties": {
          "input": {
            "type": "string",
            "description": "Free text identifying the restaurant: name plus location info (address / city / Google Maps / URL).",
            "example": "La Tagliatella, Carrer Gran de Gràcia 15, Barcelona"
          },
          "companyId": {
            "type": "string",
            "description": "Company the catalog is created for. Defaults to the authenticated session company when omitted.",
            "example": "64f1b8a2c3d4e5f6a7b8c9d0"
          },
          "force": {
            "type": "boolean",
            "description": "Re-import even if the company already has a catalog. Defaults to false (a company that already has items is skipped to avoid duplicates).",
            "example": false
          }
        },
        "required": [
          "input"
        ]
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "An API key from Settings > Developers, sent with its scheme prefix: `API Pk-XXXXXXXX`"
      }
    }
  }
}
