# Platomico API The HTTP API behind Platomico, a restaurant operations platform. This file is the whole reference: authentication, conventions, every endpoint an API key can reach, and the shape of every request and response body. It is generated from the services' own OpenAPI documents, so it describes what is deployed rather than what was once written down. Generated 2026-09-22 · 658 endpoints across 6 services · OpenAPI: `/api-docs/openapi.json` ## Authentication Every request carries an API key in the `Authorization` header, with the scheme `API` in front of it: ``` Authorization: API Pk-XXXXXXXX… ``` Keys are created in the dashboard under **Settings ▸ Developers ▸ API keys**. The key is shown once, when it is created, and is stored hashed — it cannot be read back afterwards. If it is lost, create another and revoke the old one. ```bash curl https://api.platomico.com/operations/locations \ -H "Authorization: API Pk-XXXXXXXX…" ``` ## What a key may do A key carries three limits, all set when it is created and all enforced on every request: 1. **Services.** A key reaches only the services it is scoped to. The scope names are the first path segment of the URL, so a key scoped to `operations` may call `/operations/…` and nothing else. 2. **Mode.** A `READ` key may issue only `GET` and `HEAD`. A `WRITE` key may issue any method. 3. **Locations.** A key may be pinned to specific locations. A pinned key is refused when a request names a location outside the pin, through `locationId` or `locationsIds` in the query string or the path. A request that falls outside any of the three is refused with `403`. ## Conventions - **Base URL** — `https://api.platomico.com` - **Content type** — `application/json` for every request body and response. - **Identifiers** — MongoDB ObjectIds, 24 lowercase hex characters, as strings. - **Dates** — ISO 8601 with a timezone, e.g. `2026-09-21T10:00:00.000Z`. - **Money** — integer minor units (cents), never floats. - **Company scope** — a key belongs to one company. Every response is already scoped to it; there is no company parameter to pass and no way to reach another company's data. ### Status codes | Code | Meaning | | --- | --- | | `200` / `201` | Success. | | `400` | The request body or query failed validation. | | `401` | The key is missing, unknown, revoked, expired, or belongs to a deactivated account. | | `403` | The key is valid but out of scope — wrong service, a write from a `READ` key, or a location outside its pin. | | `404` | No such record, or it belongs to another company. | | `429` | Rate limited. | ## Services | Scope | Base path | Covers | | --- | --- | --- | | `auth` | `/authentication` | Sessions, API keys and provider secrets. | | `operations` | `/operations` | Orders, locations, companies, users, members, schedules, analytics. | | `payments` | `/payments` | Transactions, discounts, taxes, payouts, cash registers. | | `supply-chain` | `/supply-chain` | Catalog and inventory: items, meals, menus, modifiers, stock. | | `integrations` | `/integrations` | Provider bindings, webhooks, channel events. | | `common` | `/common` | Files, notifications, print jobs, audit trail. | --- ## authentication Sessions, API keys and provider secrets. Base path: `/authentication` · scope name: `auth` ### Auth #### `POST /authentication/check-user` **Check whether a user exists and is valid** Given a user id, returns whether the user exists and is in a valid state. Used by downstream services during account reconciliation. Request body: `object` Responses: - `200` — Existence/validity report #### `POST /authentication/check/access-code` **Check a remote access code** Verifies that a given remote access code is valid for the calling member without consuming it. Request body: `AccessCode` Responses: - `200` — Whether the code is valid and its associated payload #### `GET /authentication/customer/session` **Get current customer session** Returns the session for a signed-in end customer. Responses: - `200` — Current customer session #### `POST /authentication/customer/session/exchange` **Exchange a customer session** Upgrades or re-scopes a customer session (e.g. attaching a real name and target company after an anonymous start). Request body: `ExchangeCustomerSession` Responses: - `200` — Exchanged customer session #### `GET /authentication/device/session` **Get current device session** Returns the session attached to the Bearer token for a paired device (POS, kiosk, etc.). Responses: - `200` — Current device session details - `401` — Missing or invalid token #### `POST /authentication/device/session/ephimeral` **Exchange an ephemeral code for a short-lived session** 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. Request body: `Code` Responses: - `200` — Short-lived ephemeral session token #### `GET /authentication/endpoint/session` **Get the endpoint session for a domain** 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. Query parameters: - `domain` (required) string — Domain requesting the endpoint session - `scope` string — Optional scope for the endpoint session Responses: - `200` — Endpoint session for the given domain/scope #### `POST /authentication/forgot-password` **Send a password recovery email** Sends the user a link/code they can use to reset their password. Request body: `object` Responses: - `200` — Recovery email dispatched #### `GET /authentication/member/session` **Get current member session** Returns the session for a signed-in member (staff user of a company). Responses: - `200` — Current member session #### `POST /authentication/remote/access-code` **Create a remote access code** 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). Request body: `CreateRemoteAccessCode` Responses: - `200` — Generated access code #### `POST /authentication/send-code` **Send an SMS verification code** Sends a code to the customer's phone using the selected SMS provider. Request body: `SmsPayload` Responses: - `200` — SMS dispatched #### `GET /authentication/session` **Get current user session** Returns the session attached to the Bearer token for a human user. Responses: - `200` — Current user session details - `401` — Missing or invalid token #### `POST /authentication/session/agent-token` **Mint a company-restricted token for an AI agent** 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. Request body: `object` Responses: - `200` — A token restricted to the target company #### `POST /authentication/session/exchange` **Switch the active company on the user session** Exchanges the current user session for one scoped to another company the user belongs to. Request body: `object` Responses: - `200` — New session with the target company active #### `POST /authentication/sign-in/with-access-code` **Sign in with a remote access code** Redeems a remote access code issued by a member to authorize a one-off action. Request body: `AccessCode` Responses: - `200` — Session or action payload associated with the code #### `POST /authentication/sign-in/with-credentials` **Sign in with email + password** Standard user sign-in. Returns a user session on success. Request body: `Credentials` Responses: - `200` — User session - `401` — Invalid credentials #### `POST /authentication/sign-in/with-customer-credentials` **Sign a customer in from an endpoint** Creates or reuses a customer record and returns a customer session for an endpoint (e.g. ordering site). Request body: `CustomerLoginPayload` Responses: - `200` — Customer session #### `POST /authentication/sign-in/with-device-code` **Sign in with a device pairing code** Completes device pairing by redeeming the short code shown on the device. Request body: `DeviceCode` Responses: - `200` — Device session #### `POST /authentication/sign-in/with-email/device` **Request a device sign-in email** Sends a one-time magic link or code to the user so they can sign in on a device. Request body: `Email` Responses: - `200` — Email dispatched #### `POST /authentication/sign-in/with-member-code` **Sign a member in from a device using a member code** Allows a member to start a session on a paired device by typing their numeric member code. Request body: `MemberCode` Responses: - `200` — Member session #### `POST /authentication/sign-in/with-member-code/endpoint` **Sign a member in from an endpoint using a member code** Same as /sign-in/with-member-code but scoped to an endpoint (embedded web) session instead of a device session. Request body: `MemberCode` Responses: - `200` — Member session #### `POST /authentication/sign-in/with-member-credentials` **Sign a member in with email + code** Verifies the numeric code previously emailed/sent to the member and returns a member session. Request body: `MemberSignIn` Responses: - `200` — Member session - `401` — Invalid or expired code #### `POST /authentication/sign-up/device` **Complete device sign-up** Creates the company, primary location, and device records using an ephemeral session obtained from /device/session/ephimeral. Request body: `SignUpFromDevice` Responses: - `200` — Device session after successful sign-up #### `POST /authentication/sign-up/web` **Sign up from the web** Creates a new user account. Requires a verification token from /sign-up/web/verify-code. Request body: `SignUpFromWeb` Responses: - `200` — Created user session #### `POST /authentication/sign-up/web/request-code` **Request a sign-up verification code** Sends a one-time code to the email to prove ownership before allowing sign-up. Request body: `object` Responses: - `200` — Code dispatched #### `POST /authentication/sign-up/web/verify-code` **Verify a sign-up code** Validates the code emailed in the previous step and returns a verificationToken to use in /sign-up/web. Request body: `object` Responses: - `200` — Verification token to attach to /sign-up/web #### `GET /authentication/token` **Fetch a token by lookup key** Retrieves a previously stored token for the given lookup key and user type. Used in flows that need to resume a handoff by reference. Query parameters: - `key` (required) string — Lookup key for the stored token - `userType` (required) string — Type of user the token belongs to Responses: - `200` — Stored token payload #### `POST /authentication/verify-code` **Verify an SMS code** Validates a code previously sent via /send-code and attaches the phone to the customer's session. Request body: `SmsPayload` Responses: - `200` — Verification result ### Health #### `GET /authentication/health` **Service health check** Returns the health status of the authentication service and its dependencies. Used by load balancers and uptime monitors. Responses: - `200` — Health details per subsystem ### authentication schemas #### `AccessCode` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `code` | `string` | yes | Remote access code | #### `Code` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `code` | `string` | yes | Verification or exchange code | #### `CreateApiKey` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Operator-facing label | | `services` | `string[]` | yes | Gateway prefixes this key may call | | `mode` | `string` | yes | READ keys may only issue GET and HEAD | | `locationsIds` | `string[]` | no | Locations this key may name. [] or ['*'] means every one. | | `expiresAt` | `string` | no | ISO date after which the key stops working. Absent = never. | #### `CreateDeviceCode` Type: `object` #### `CreateRemoteAccessCode` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `endpoint` | `string` | yes | Target endpoint domain the remote access code will authorize | | `payload` | `object` | yes | Arbitrary payload associated with the access code | #### `CreateSecret` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Company the secret belongs to | | `contractId` | `string` | no | Optional contract (provider binding) the secret belongs to | | `provider` | `string` | yes | Provider that owns the secret | | `value` | `string` | yes | Secret value (will be encrypted at rest) | | `tag` | `string` | yes | Tag to disambiguate secrets of the same provider | #### `Credentials` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | User's email address | | `password` | `string` | yes | User's password | #### `CustomerLoginPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | Customer's email address | | `name` | `string` | yes | Customer's first name | | `lastname` | `string` | no | Customer's last name | | `birthdate` | `string` | no | Customer's date of birth | | `phone` | `object` | no | Customer's phone number with country prefix | #### `DeviceCode` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `code` | `string` | yes | Device pairing code | #### `Email` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | Email address | #### `ExchangeCustomerSession` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name under which to exchange the session | | `companyId` | `string` | yes | Target company ID | #### `FetchSecret` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `tag` | `string` | no | Optional tag to disambiguate secrets of the same provider | | `companyId` | `string` | yes | Company the secret belongs to | | `provider` | `string` | yes | Provider that owns the secret | #### `MemberCode` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `code` | `number` | yes | Numeric member sign-in code | #### `MemberSignIn` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | Member's email address | | `code` | `number` | yes | Numeric member sign-in code | #### `SignUpFromDevice` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `company` | `object` | yes | Company billing and identity details | | `location` | `object` | yes | Physical location where the device operates | | `device` | `object` | yes | Device metadata | #### `SignUpFromWeb` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | New user's email address | | `password` | `string` | yes | Password to set for the new account | | `name` | `string` | yes | User's full name | | `verificationToken` | `string` | yes | Token issued by the email verification step | #### `SmsPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `code` | `string` | yes | Verification code sent to the user (empty when requesting a new code) | | `phone` | `object` | yes | Phone number with country prefix | | `provider` | `string` | yes | SMS gateway to use | | `token` | `string` | no | Anti-abuse token (e.g. reCAPTCHA) when requesting a new code | #### `UpdateApiKey` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | | | `services` | `string[]` | no | | | `mode` | `string` | no | | | `locationsIds` | `string[]` | no | | | `expiresAt` | `string` | no | ISO date, or null to clear the expiry | | `active` | `boolean` | no | Pause a key without revoking it | #### `VerifyPermission` Type: `object` --- ## operations Orders, locations, companies, users, members, schedules, analytics. Base path: `/operations` · scope name: `operations` ### Analytics #### `GET /operations/analytics/delivery/fleets` **Fetch delivery fleets serving the current company** Responses: - `200` #### `GET /operations/analytics/delivery/metrics` **Fetch delivery KPI metrics for a date range** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` #### `GET /operations/analytics/delivery/metrics/by-location` **Fetch delivery KPI metrics grouped by location** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` #### `GET /operations/analytics/delivery/offers/summary` Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` #### `GET /operations/analytics/delivery/orders/by-location` **Fetch individual delivery orders for a location and date range** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` #### `GET /operations/analytics/delivery/stacks/{stackIdentifier}` **Fetch delivery stack detail scoped to the current company** Path parameters: - `stackIdentifier` (string) Responses: - `200` #### `GET /operations/analytics/gross/sales` **Fetch gross sales totals** Returns the gross sales (before discounts and refunds) for the given locations within the time window. Used by dashboards to present top-line revenue. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` — Gross sales totals keyed by location #### `GET /operations/analytics/items/sales-amount` **Fetch per-item sales amounts** Returns total sold amount per menu item across the given locations and time window. Used for top-sellers reports. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate item sales for Responses: - `200` — Per-item sales amounts #### `GET /operations/analytics/net/sales` **Fetch net sales totals** Returns net sales (gross minus discounts, refunds and taxes) for the given locations within the time window. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` — Net sales totals keyed by location #### `GET /operations/analytics/sales-by-hour` **Fetch sales aggregated by hour of day** Returns sales totals bucketed by hour of day (0-23). Used to render hourly distribution charts and staffing insights. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for - `serviceType` string — Narrow to one service type. DINE_IN, TAKE_AWAY or DELIVERY; ALL or absent leaves every order in. - `source` string — 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. Responses: - `200` — Sales totals per hour of the day (0-23) #### `GET /operations/analytics/times/by-location` **Fetch operational times grouped by location and day** 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. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for - `timezone` string — IANA timezone used to bucket the results by calendar day Responses: - `200` — Time sums/counts per location per day ### Analytics:V2 #### `GET /operations/analytics/v2/delivery/metrics` **Fetch delivery metrics (time-of-day aware)** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `source` string — Filter by origin source/channel (prep-time stats) - `serviceType` string — Filter by service type (prep-time stats) Responses: - `200` #### `GET /operations/analytics/v2/delivery/metrics/by-location` **Fetch delivery metrics by location (time-of-day aware)** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `source` string — Filter by origin source/channel (prep-time stats) - `serviceType` string — Filter by service type (prep-time stats) Responses: - `200` #### `GET /operations/analytics/v2/orders/prep-time-stats` **Fetch prep-time statistics (time-of-day aware)** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `source` string — Filter by origin source/channel (prep-time stats) - `serviceType` string — Filter by service type (prep-time stats) Responses: - `200` #### `GET /operations/analytics/v2/times/by-location` **Fetch operational times by location and day (time-of-day aware)** Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `source` string — Filter by origin source/channel (prep-time stats) - `serviceType` string — Filter by service type (prep-time stats) Responses: - `200` ### Audits #### `POST /operations/ernesto/audits` **Submit an audit response** Records the member responses for one audit run. Can be saved as a draft (draft: true) and finalized later. Request body: `CreateAuditResponse` Responses: - `200` — Stored audit response #### `GET /operations/ernesto/audits` **List audits for a location** Returns the most recent audit responses filed at the given location, sorted most-recent-first. Query parameters: - `locationId` (required) string Responses: - `200` — Audits recorded at the location #### `GET /operations/ernesto/audits/{identifier}` **Fetch an audit response by identifier** Returns the full audit response (questions, answers, images) for the given identifier. Path parameters: - `identifier` (string) Responses: - `200` — Audit response details #### `GET /operations/ernesto/audits/types` **List available audit types** Returns every audit template (cleanliness, opening checklist, etc.) available to the member. Used by the dashboard to build the audit picker. Responses: - `200` — Available audit types with their questions #### `GET /operations/ernesto/audits/types/{identifier}` **Fetch an audit type by identifier** Returns the full definition (questions, choices, photo requirements) for a single audit type. Path parameters: - `identifier` (string) Responses: - `200` — Full audit type definition ### Companies #### `GET /operations/companies/settings` **Fetch company settings** Returns the active company profile and settings for the signed-in user (branding, billing, socials, legal, feature flags). Responses: - `200` — Company profile and settings #### `PATCH /operations/companies/settings` **Update company settings** Updates branding, billing, name/type or logo on the active company. Requires admin-level roles. Request body: `UpdateSettings` Responses: - `200` — Updated company settings #### `GET /operations/companies/status/device` **Fetch company status from a device** Used by paired devices to read the company onboarding/operational status without pulling the full settings payload. Responses: - `200` — Company operational status ### Customers #### `GET /operations/customers` **List customers for the active company** 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. Query parameters: - `page` string - `pageSize` string - `search` string - `createdAtFrom` string - `createdAtTo` string Responses: - `200` — Customers matching the query #### `GET /operations/customers/statistics` **Customer-base statistics for the active company** 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. Query parameters: - `createdAtFrom` (required) string - `createdAtTo` (required) string - `previousCreatedAtFrom` (required) string - `previousCreatedAtTo` (required) string Responses: - `200` — Customer-base counts for the two windows ### Delivery #### `GET /operations/delivery` **Fetch delivery orders for current company** Query parameters: - `offset` string - `limit` string - `to` string - `from` string - `status` string Responses: - `200` #### `POST /operations/delivery` **Create a delivery order for current company** Request body: `CreateDeliveryOrderDto` Responses: - `201` #### `PATCH /operations/delivery/{orderId}/cancel` **Cancel a delivery order** Path parameters: - `orderId` (string) Request body: `CancelDeliveryOrderDto` Responses: - `200` #### `PATCH /operations/delivery/{orderId}/courier` **Reassign the courier for a delivery order** Path parameters: - `orderId` (string) Request body: `ReassignCourierDto` Responses: - `200` #### `GET /operations/delivery/by-id` **Fetch a delivery order by ID** Query parameters: - `orderId` (required) string Responses: - `200` #### `POST /operations/delivery/couriers` **Invite a new courier to a fleet** Request body: `InviteCourier` Responses: - `201` #### `DELETE /operations/delivery/couriers/{courierId}` **Delete a courier** Path parameters: - `courierId` (string) Responses: - `200` #### `PATCH /operations/delivery/couriers/{courierId}/configuration` **Update courier configuration (e.g. maximumActiveOrders)** Path parameters: - `courierId` (string) Request body: `UpdateCourierConfigurationDto` Responses: - `200` #### `GET /operations/delivery/couriers/{courierId}/configuration` **Fetch courier configuration (e.g. maximumActiveOrders)** Path parameters: - `courierId` (string) Responses: - `200` #### `PATCH /operations/delivery/couriers/{courierId}/locations` **Update locations covered by a courier** Path parameters: - `courierId` (string) Request body: `UpdateCourierLocationsDto` Responses: - `200` #### `POST /operations/delivery/couriers/password-reset/confirm` **Confirm a courier password reset with token** Responses: - `201` #### `POST /operations/delivery/couriers/password-reset/request` **Request a password reset email for a courier** Responses: - `201` #### `POST /operations/delivery/couriers/resend-invite` **Resend courier invite email** Responses: - `201` #### `GET /operations/delivery/fleets` **Fetch delivery fleets for current company** Responses: - `200` #### `PATCH /operations/delivery/fleets/{fleetId}/locations` **Update locations covered by a fleet** Path parameters: - `fleetId` (string) Responses: - `200` #### `GET /operations/delivery/fleets/metrics` **Fetch per-fleet performance metrics for current company** Query parameters: - `from` (required) string - `to` (required) string - `fleetId` string Responses: - `200` #### `GET /operations/delivery/metrics` **Fetch delivery operational KPIs for current company** Query parameters: - `from` (required) string - `to` (required) string Responses: - `200` #### `GET /operations/delivery/metrics/timeseries` **Fetch delivery time-series for current company** Query parameters: - `from` (required) string - `to` (required) string - `granularity` string - `userIdentifier` string - `fleetId` string Responses: - `200` #### `GET /operations/delivery/offers` **Fetch delivery offers for current company** Query parameters: - `offset` string - `limit` string - `to` string - `from` string - `userIdentifier` string - `status` string Responses: - `200` #### `GET /operations/delivery/offers/by-id` **Fetch a delivery offer by ID** Query parameters: - `offerId` (required) string Responses: - `200` #### `GET /operations/delivery/offers/by-order` **Fetch offer book for a delivery order** Query parameters: - `orderId` (required) string Responses: - `200` #### `GET /operations/delivery/offers/summary` **Fetch delivery offer summary/KPIs for current company** Query parameters: - `from` (required) string - `to` (required) string Responses: - `200` #### `GET /operations/delivery/paged` **Fetch a page of delivery orders with the total matching the filter** Query parameters: - `offset` string - `limit` string - `to` string - `from` string - `status` string Responses: - `200` #### `GET /operations/delivery/performance-thresholds` **Fetch performance thresholds by scope (merchant:location)** Responses: - `200` #### `PATCH /operations/delivery/performance-thresholds` **Upsert the performance threshold for a scope (merchant:location)** Request body: `UpdatePerformanceThresholdDto` Responses: - `200` #### `GET /operations/delivery/pickup-locations` **Fetch pickup locations authorized for current session** Responses: - `200` #### `GET /operations/delivery/reports/attendance` **Fetch rider attendance report for current company** Query parameters: - `from` (required) string - `to` (required) string - `fleetId` string - `locationId` string Responses: - `200` #### `GET /operations/delivery/riders` **Fetch all riders (users with workdays) for current company** Responses: - `200` #### `GET /operations/delivery/riders/{userIdentifier}/orders` **Fetch active orders for a specific rider** Path parameters: - `userIdentifier` (string) Responses: - `200` #### `GET /operations/delivery/riders/{userIdentifier}/sessions` **Fetch workday sessions for a specific rider** Path parameters: - `userIdentifier` (string) Query parameters: - `offset` string - `limit` string - `to` string - `from` string Responses: - `200` #### `GET /operations/delivery/riders/{userIdentifier}/sessions/count` **Count workday sessions for a specific rider** 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. Path parameters: - `userIdentifier` (string) Query parameters: - `to` string - `from` string Responses: - `200` #### `GET /operations/delivery/riders/{userIdentifier}/stats` **Fetch hour stats for a specific rider** Path parameters: - `userIdentifier` (string) Query parameters: - `month` string Responses: - `200` #### `GET /operations/delivery/riders/contract-summary` **Fetch per-rider assigned vs contracted hours for a date range** Query parameters: - `from` (required) string - `to` (required) string - `fleetId` string Responses: - `200` #### `GET /operations/delivery/riders/metrics` **Fetch per-rider performance metrics for current company** Query parameters: - `from` (required) string - `to` (required) string - `userIdentifier` string Responses: - `200` #### `GET /operations/delivery/stacks/{stackIdentifier}` **Fetch the composition of a delivery stack** Path parameters: - `stackIdentifier` (string) Responses: - `200` #### `GET /operations/delivery/summary` **Fetch delivery summary/KPIs for current company** Query parameters: - `from` (required) string - `to` (required) string Responses: - `200` #### `PATCH /operations/delivery/support/requests/{requestIdentifier}/status` **Update the status of a courier support request** Path parameters: - `requestIdentifier` (string) Request body: `UpdateSupportRequestStatusDto` Responses: - `200` #### `GET /operations/delivery/support/requests/manage` **Fetch courier support requests for current company** Query parameters: - `status` string Responses: - `200` #### `GET /operations/delivery/support/requests/manage/count` **Count courier support requests for current company** 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. Query parameters: - `status` string Responses: - `200` #### `GET /operations/delivery/support/requests/manage/paged` **List a page of courier support requests with the matching total** Same filter as the list endpoint, narrowed to one page. Courier, fleet and resolver names are resolved only for the rows on the page. Query parameters: - `status` string - `skip` string - `limit` string - `search` string — Matches the request description, the courier name, and any issue or topic identifier listed in `labels`. - `labels` array — Issue or topic identifiers whose label matched the search term in the caller locale, resolved by the caller so the service stays locale-agnostic. Responses: - `200` #### `GET /operations/delivery/tracking` **Fetch active riders with their current location** Responses: - `200` #### `GET /operations/delivery/tracking/order` **Fetch delivery tracking details for a specific order and workday** Query parameters: - `workdayId` (required) string - `orderId` (required) string Responses: - `200` ### Devices #### `GET /operations/devices` **List devices** Returns every device belonging to the active company, optionally filtered by location ids. Query parameters: - `locationsIds` (required) string[] — Locations to scope the query to Responses: - `200` — Devices matching the query #### `POST /operations/devices` **Create a device** Registers a new device (POS, kiosk, printer, kitchen display) at a location. Request body: `CreateDevice` Responses: - `200` — Created device #### `PATCH /operations/devices` **Update a device** Partially updates a device record (name, description, status, network, trace metadata). Request body: `UpdateDevice` Responses: - `200` — Updated device #### `DELETE /operations/devices` **Delete a device** Removes a device from the company. The device becomes unreachable and any remaining session is revoked. Query parameters: - `deviceId` (required) string Responses: - `200` — Deletion result #### `GET /operations/devices/code` **Fetch a pairing code for a device** Generates (or returns a fresh) pairing code that can be entered on the physical device to complete pairing. Query parameters: - `locationId` (required) string — Location the device belongs to - `deviceId` (required) string — Device to issue a pairing code for Responses: - `200` — Pairing code #### `POST /operations/devices/exec/action` **Execute a remote action on devices** Broadcasts a command (LOGOUT, RELOAD) to the targeted device or all devices in the given locations. Request body: `ExecAction` Responses: - `200` — Delivery result for the command #### `POST /operations/devices/heartbeat` **Post a device heartbeat** Called periodically by devices to report liveness, app/os version and platform. Updates the lastSeenAt field. Request body: `PostHeartbeat` Responses: - `200` — Heartbeat acknowledged #### `GET /operations/devices/linked` **List devices linked to the caller device** Returns every device that is paired with the caller device (e.g. printers or KDS attached to a POS). Responses: - `200` — Linked devices #### `GET /operations/devices/one` **Fetch a device by id** Returns the full device document for a single device id. Query parameters: - `deviceId` (required) string Responses: - `200` — Device details #### `POST /operations/devices/peripheral-offline` **Mark a USB peripheral as offline immediately** 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. Request body: `PeripheralOffline` Responses: - `200` — Peripheral connectivity flipped to OFFLINE #### `GET /operations/devices/preferences` **Fetch the calling device's own app preferences** 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. Responses: - `200` — Stored preferences, sparse (absent key = client default) #### `PATCH /operations/devices/preferences` **Update a device's app preferences** 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. Request body: `UpdateDevicePreferences` Responses: - `200` — Updated device #### `GET /operations/devices/session` **Fetch the current device session** Returns the device-scoped (or impersonating member) session for the Bearer token. Used by the device shell at boot. Responses: - `200` — Device or member session details ### Devices:Settings #### `GET /operations/devices/settings` **Fetch settings by location** Returns the device-settings documents matching the given location ids. Query parameters: - `locationsIds` (required) string[] — Locations to scope the query to Responses: - `200` — Settings documents for the locations #### `POST /operations/devices/settings` **Create a device settings document** Creates a new device settings (layout, theme, terminal, features) for the active company. Request body: `Settings` Responses: - `200` — Created settings document #### `PATCH /operations/devices/settings` **Update a settings document** Partial update of an existing device settings document (any field except the identity). Query parameters: - `settingsId` (required) string Request body: `Settings` Responses: - `200` — Updated settings document #### `DELETE /operations/devices/settings` **Delete a settings document** Removes a device settings document from the caller company. Query parameters: - `settingsId` (required) string Responses: - `200` — Deletion result #### `GET /operations/devices/settings/all` **List every settings document for the company** Returns every device-settings document configured in the active company (used by the back-office to pick a layout to clone). Responses: - `200` — Settings documents #### `PATCH /operations/devices/settings/bulk-grid` **Bulk-update the UI grid** Applies the same grid layout to several locations (and optionally specific settings ids) at once. Request body: `BulkGridUpdate` Responses: - `200` — Update result #### `GET /operations/devices/settings/one` **Fetch a settings document by id** Returns the full settings document for the given id. Query parameters: - `settingsId` (required) string Responses: - `200` — Settings document ### Devices:V2 #### `POST /operations/devices/v2` **Create a device (v2)** Registers a new device using the v2 creation pipeline which adds defaults and richer validation over the legacy endpoint. Request body: `CreateDevice` Responses: - `200` — Created device #### `PATCH /operations/devices/v2` **Update a device (v2)** Partially updates a device record using the v2 update pipeline. Should be preferred over the legacy PATCH endpoint. Request body: `UpdateDevice` Responses: - `200` — Updated device ### Endpoints #### `POST /operations/endpoints` **Create an endpoint** Creates a new endpoint (embedded ordering/QR site) with its branding and domain bindings for the active company. Request body: `CreateEndpoint` Responses: - `200` — Created endpoint #### `PATCH /operations/endpoints/{endpointId}` **Update the identity of an endpoint** 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. Path parameters: - `endpointId` (string) Request body: `UpdateEndpoint` Responses: - `200` — Updated endpoint #### `PATCH /operations/endpoints/{endpointId}/domains` **Replace the ordered domains of an endpoint** 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. Path parameters: - `endpointId` (string) Request body: `UpdateEndpointDomains` Responses: - `200` — Updated endpoint #### `PATCH /operations/endpoints/{endpointId}/settings` **Update the branding and style overrides of an endpoint** 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. Path parameters: - `endpointId` (string) Request body: `UpdateEndpointSettings` Responses: - `200` — Updated endpoint #### `GET /operations/endpoints/by-company` **List endpoints for the active company** Returns every endpoint configured for the caller company, with their domains and settings. Responses: - `200` — Endpoints for the company #### `GET /operations/endpoints/provider` **Fetch provider configuration by domain** Returns terminal/online/delivery provider configuration for the endpoint matching the given domain. Used by the embedded checkout to pick SDKs. Query parameters: - `domain` (required) string Responses: - `200` — Provider configuration #### `GET /operations/endpoints/seo` **Fetch SEO metadata by domain** Public endpoint used by server-side rendered frontends to bootstrap page title/description/og image for a given domain. Query parameters: - `domain` (required) string Responses: - `200` — SEO metadata for the domain ### Health #### `GET /operations/health` **Check operations service health** Public liveness probe that reports the health status of the operations service and its critical dependencies. Responses: - `200` — Health details for each critical dependency ### Incidents #### `GET /operations/incidents` **List incidents for current company** Query parameters: - `status` string Responses: - `200` #### `POST /operations/incidents` **Create an incident for current company** Request body: `CreateIncidentDto` Responses: - `201` #### `GET /operations/incidents/{incidentId}` **Fetch a single incident by id** Path parameters: - `incidentId` (string) Responses: - `200` ### Invoices #### `GET /operations/invoices` **Fetch invoices for a customer** Returns every invoice linked to the given customer id within the active company. Query parameters: - `customerId` (required) string Responses: - `200` — Invoices linked to the customer #### `POST /operations/invoices` **Create an invoice from a receipt** Generates an invoice number and persists the invoice for the given receipt. Legacy payload; prefer /endpoint or /dashboard. Request body: `CreateInvoice` Responses: - `200` — Created invoice #### `GET /operations/invoices/{invoiceId}/pdf` **Download invoice PDF** Streams the invoice PDF. Accepts an optional locale for the PDF copy (default: es). Sets content-disposition to attachment. Path parameters: - `invoiceId` (string) Query parameters: - `locale` string Responses: - `200` — PDF binary stream #### `POST /operations/invoices/dashboard` **Create an invoice from the dashboard** v2 invoice creation called from the back-office dashboard. Internally maps the user session to an endpoint-like payload. Request body: `CreateInvoiceV2` Responses: - `200` — Created invoice #### `POST /operations/invoices/endpoint` **Create an invoice from an endpoint** v2 invoice creation called from the embedded checkout (endpoint session). Requires the originating transactionId. Request body: `CreateInvoiceV2` Responses: - `200` — Created invoice #### `POST /operations/invoices/export-email` **Export invoices by email** Enqueues an export job that sends a ZIP with the selected invoice PDFs to the target email address. Request body: `ExportInvoicesByEmail` Responses: - `200` — Export job queued #### `GET /operations/invoices/paginated` **List invoices (paginated)** Returns invoices belonging to the active company with optional text search and createdAt range, paginated with page/pageSize. Query parameters: - `page` (required) string - `pageSize` (required) string - `search` string - `createdAtFrom` string - `createdAtTo` string Responses: - `200` — Paginated invoices #### `GET /operations/invoices/statistics` **Invoice totals for the active company** 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. Query parameters: - `createdAtFrom` (required) string - `createdAtTo` (required) string - `previousCreatedAtFrom` (required) string - `previousCreatedAtTo` (required) string - `search` string Responses: - `200` — Invoice totals for the two windows, amounts in cents #### `GET /operations/invoices/transaction` **Fetch a transaction by receipt id + date** Looks up the transaction that generated the given receipt on the specified date. Used when the invoice flow starts from a printed ticket. Query parameters: - `receiptId` (required) string - `date` (required) string Responses: - `200` — Matching transaction ### Locations #### `POST /operations/locations` **Create a location (deprecated)** Legacy location creation endpoint. New integrations should use POST /locations/v2. Request body: `CreateLocation` Responses: - `200` — Created location #### `GET /operations/locations` **List locations** Returns every location accessible to the signed-in user. Optional locationsIds filter returns only matching ids. Query parameters: - `locationsIds` (required) string[] — Locations to scope the query to Responses: - `200` — Locations accessible to the caller #### `PATCH /operations/locations/auto-print` **Update automatic printing exclusions** 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. Request body: `UpdateAutoPrintDto` Responses: - `200` — Update result #### `GET /operations/locations/delivery-live-timers` **Fetch per-location timer settings for the live kanban** Returns the deliveryLiveTimers block for each requested location, with defaults filled in when not yet configured. Query parameters: - `locationsIds` (required) string[] — Locations to fetch timer settings for Responses: - `200` — Per-location timer settings #### `PUT /operations/locations/delivery-live-timers` **Update timer settings for a single location** Upserts the deliveryLiveTimers block on settings. Validates that values come from the allowed minutes set and that "late" >= "soon". Request body: `UpdateDeliveryLiveTimersDto` Responses: - `200` — Updated timer settings #### `GET /operations/locations/device` **Fetch the location attached to a device** Returns the location bound to the calling device session. Used at device boot to load currency/timezone/printers. Responses: - `200` — Location attached to the device session #### `GET /operations/locations/endpoint` **Fetch locations for an endpoint session** Returns the locations available to the calling endpoint session (embedded ordering/QR frontends), optionally filtered by ids. Query parameters: - `locationsIds` string[] Responses: - `200` — Locations for the endpoint #### `GET /operations/locations/fetch-by-companies` **List locations across all reachable companies** Returns locations for every company the user belongs to. Useful for multi-brand dashboards. Responses: - `200` — Locations grouped by company #### `PATCH /operations/locations/pos` **Update POS behaviour flags** Replaces the POS behaviour configuration (e.g. autoComplete on "Done") for the given locations. Request body: `UpdatePosDto` Responses: - `200` — Update result #### `PATCH /operations/locations/tickets` **Update ticket printing flags** Replaces the ticket printing configuration (receipt, kitchenReceipt) for the given locations. Request body: `UpdateTicketsDto` Responses: - `200` — Update result #### `POST /operations/locations/v2` **Create a location (v2)** Creates a physical location for the active company with currency, timezone, branding, workdays and ticket settings. Request body: `CreateLocationV2` Responses: - `200` — Created location #### `PATCH /operations/locations/workdays` **Update workdays for one or more locations** Replaces the weekly workdays schedule (opening hours) for the given locations. Request body: `UpdateWorkdaysDto` Responses: - `200` — Update result ### Loyalty #### `POST /operations/loyalty/programs` **Create a loyalty program** Creates a new loyalty program (stamps, points, tiered) for the active company and its locations. Request body: `CreateProgram` Responses: - `200` — Created program #### `GET /operations/loyalty/programs` **List loyalty programs** Returns every loyalty program visible to the signed-in user. Responses: - `200` — Loyalty programs #### `PATCH /operations/loyalty/programs` **Update a loyalty program** Partial update of a loyalty program owned by the caller company. Responses: - `200` — Updated program #### `DELETE /operations/loyalty/programs` **Delete a loyalty program** Removes a loyalty program owned by the caller company. Responses: - `200` — Deletion result #### `POST /operations/loyalty/programs/benefits` **Create a loyalty benefit** Attaches a benefit (discounted or free item/meal/discount) to a loyalty program, with redemption constraints (auto-apply, quotas, time window). Request body: `CreateBenefit` Responses: - `200` — Created benefit #### `GET /operations/loyalty/programs/passes/device` **Fetch a pass from a device** Returns the pass details used by a device (e.g. POS) to render loyalty state for the scanned customer. Query parameters: - `id` (required) string — Pass id Responses: - `200` — Pass details #### `DELETE /operations/loyalty/programs/passes/device` **Log a pass out from a device** Detaches the currently-scanned pass from the device session, returning the device to the neutral state. Query parameters: - `id` (required) string — Pass id Responses: - `200` — Logout acknowledged #### `GET /operations/loyalty/programs/passes/endpoint` **Fetch a customer pass from an endpoint** Returns the calling customer pass for the given program id, as seen from an embedded endpoint (ordering/QR). Query parameters: - `pid` (required) string — Loyalty program id Responses: - `200` — Pass details for the customer #### `GET /operations/loyalty/programs/passes/join` **Join a loyalty program** Customer endpoint to join a program and receive a wallet pass (Apple or Google) bound to the chosen template. Query parameters: - `programId` (required) string — Loyalty program to join - `templateId` (required) string — Template used for the generated wallet pass - `provider` (required) string — Wallet provider the pass should be generated for Responses: - `200` — Generated pass + wallet install link #### `POST /operations/loyalty/programs/reward` **Create a loyalty reward** Attaches a reward (free item or discount) to an existing program. Customers earn these when they reach program milestones. Request body: `createReward` Responses: - `200` — Created reward #### `POST /operations/loyalty/programs/templates` **Create a wallet template** Creates a Google/Apple Wallet template (style + fields) bound to a loyalty program and color palette. Request body: `CreateTemplate` Responses: - `200` — Created template #### `GET /operations/loyalty/programs/templates` **List templates** Returns templates visible to the signed-in user. (WIP stub) Responses: - `200` — Templates #### `PATCH /operations/loyalty/programs/templates` **Update a template** Partial update of a loyalty template owned by the caller company. Responses: - `200` — Updated template #### `DELETE /operations/loyalty/programs/templates` **Delete a template** Removes a loyalty template owned by the caller company. Responses: - `200` — Deletion result #### `GET /operations/loyalty/programs/templates/colors` **List wallet color palettes** Returns wallet color palettes available for the given locations. Query parameters: - `locationsIds` (required) string[] — Locations to scope the query to Responses: - `200` — Color palettes #### `GET /operations/loyalty/programs/templates/device` **Fetch templates for a device** Returns every template available to the calling device (used to preview passes before printing). Responses: - `200` — Templates #### `GET /operations/loyalty/programs/templates/endpoint` **Fetch a template from an endpoint** Returns the wallet template for a (program, template) pair, called from an embedded endpoint. Query parameters: - `pid` (required) string — Program id - `tid` (required) string — Template id Responses: - `200` — Template details ### Member Absence Requests #### `POST /operations/members/me/absence-requests` **Create an absence request for the caller member** Request body: `CreateAbsenceRequestDto` Responses: - `201` #### `GET /operations/members/me/absence-requests` **List the caller member's absence requests** Query parameters: - `status` string Responses: - `200` #### `DELETE /operations/members/me/absence-requests/{requestId}` **Cancel a pending absence request** Path parameters: - `requestId` (string) Responses: - `200` ### Members #### `GET /operations/members` **List members** Returns members belonging to the caller company, optionally filtered by location ids. Responses: - `200` — Members visible to the caller #### `POST /operations/members` **Create a member** Creates a new member for the active company and locations. An invitation email is sent when an email is provided. Request body: `Member` Responses: - `200` — Created member #### `PATCH /operations/members` **Update a member** Partial update of a member record. Request body: `UpdateMember` Responses: - `200` — Updated member #### `DELETE /operations/members` **Delete a member** Removes a member from the active company. Query parameters: - `id` (required) string Responses: - `200` — Deletion result #### `PATCH /operations/members/activate` **Activate a member** Marks a member as active so that their pin code can be used to sign in on a device. Request body: `object` Responses: - `200` — Activation result #### `PATCH /operations/members/bulk` **Bulk update member roles** 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. Request body: `BulkUpdateRole` Responses: - `200` — Per-member result of the bulk role update #### `POST /operations/members/onboard/complete` **Complete member onboarding via magic link** 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. Request body: `object` Responses: - `200` — Granted member session #### `GET /operations/members/one` **Fetch a member by id** Returns the full member document for the given id. Query parameters: - `id` (required) string Responses: - `200` — Member details #### `POST /operations/members/resend` **Resend a member invitation** Re-sends the member invitation email (used when the original one was lost or expired). Request body: `object` Responses: - `200` — Invitation dispatched #### `POST /operations/members/verify` **Verify a member's email code** Validates the numeric code sent to the member email as part of invitation completion. Request body: `object` Responses: - `200` — Verification result ### Members Attendance #### `GET /operations/members/attendance` **Member attendance report** 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. Query parameters: - `locationId` string - `to` (required) string - `from` (required) string Responses: - `200` — Attendance report for members in scope ### Members Timeclock #### `POST /operations/members/{memberId}/timeclock/clock-in` **Clock a member in** Opens an ACTIVE clock session for the member. Rejects with ALREADY_CLOCKED_IN if one is already open. Path parameters: - `memberId` (string) Request body: `ClockInDto` Responses: - `200` — Opened clock session #### `POST /operations/members/{memberId}/timeclock/clock-out` **Clock a member out** Closes the ACTIVE clock session (sets out + elapsed). No active session is a no-op 200. Path parameters: - `memberId` (string) Request body: `ClockOutDto` Responses: - `200` — Closed clock session, or no-op when none active #### `GET /operations/members/{memberId}/timeclock/status` **Member clock status** Returns whether the member currently has an ACTIVE session. Path parameters: - `memberId` (string) Responses: - `200` — Current clock status #### `GET /operations/members/me/shift/today` **Resolve the caller member's shift for a day** 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. Query parameters: - `date` string Responses: - `200` — Resolved shift for the day #### `GET /operations/members/timeclock` **List member clock sessions** Returns clock sessions within the [from,to] range for the caller company, optionally filtered by location. Query parameters: - `locationId` string - `to` (required) string - `from` (required) string Responses: - `200` — Clock sessions in range #### `POST /operations/members/timeclock/clock-by-code` **Clock a member in/out by PIN code on the device** 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. Request body: `ClockByCodeDto` Responses: - `200` — Clock receipt { type, memberName, clock } #### `GET /operations/members/timeclock/config` **Clock methods enabled for the caller company** 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. Responses: - `200` — Enabled clock methods #### `GET /operations/members/timeclock/qr-token` **Mint a rotating clock-in QR token** 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. Responses: - `200` — Signed QR token and its validity window ### Onboarding #### `POST /operations/onboarding` **Scrape a menu during onboarding** 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. Request body: `object` Responses: - `200` — Scraped menu and side data #### `GET /operations/onboarding/progress` **Read onboarding progress** Returns the saved onboarding wizard progress for the authenticated user, or null if none exists. Responses: - `200` — Saved onboarding progress or null #### `PUT /operations/onboarding/progress` **Upsert onboarding progress** Idempotent whole-object upsert of the onboarding wizard progress for the authenticated user. Request body: `OnboardingProgressDto` Responses: - `200` — Stored onboarding progress ### Orders #### `PATCH /operations/orders` **Update an order** Updates an order (items, customer info, delivery info, state, priority). Called by the back-office or from the POS. Request body: `UpdateOrder` Responses: - `200` — Updated order #### `GET /operations/orders/device` **List orders from a device** 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. Query parameters: - `state` string[] — Lifecycle states to include - `stationId` string — Station identifier to restrict results to Responses: - `200` — Orders visible to the device #### `PATCH /operations/orders/device` **Update order state from a device** Moves the order to a new state (PENDING, IN_PROCESS, COMPLETED, CANCELLED) from a device (KDS or POS). Request body: `UpdateOrderState` Responses: - `200` — Updated order #### `PATCH /operations/orders/device/advance-station` **Move a SEQUENTIAL-flow order to its next/previous station** 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. Request body: `AdvanceOrderStation` Responses: - `200` — New route position and station pointers #### `GET /operations/orders/device/by-id` **Fetch an order by id from a device** 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. Query parameters: - `id` (required) string — Order identifier to fetch Responses: - `200` — Order details #### `PATCH /operations/orders/device/item-ready` **Toggle the ready flag on an order item from a device** 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. Request body: `UpdateOrderItemReady` Responses: - `200` — Item ready flag updated #### `PATCH /operations/orders/device/items-ready` **Toggle ready flags on multiple order slots from a device (atomic)** 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. Request body: `UpdateOrderItemsReady` Responses: - `200` — Item ready flags updated #### `PATCH /operations/orders/device/seen` **Stamp seenAt when a KDS device first renders an order** 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. Request body: `MarkOrderSeen` Responses: - `200` — Stamp result #### `GET /operations/orders/ernesto` **Ernesto: specific item sales for a date range** Bespoke analytics endpoint for the Ernesto dashboard. Returns per-item sales aggregated across the range for items whose names contain the substring. Query parameters: - `locationId` (required) string - `itemName` (required) string - `from` (required) string - `to` (required) string Responses: - `200` — Per-item sales aggregate #### `GET /operations/orders/ernesto/record` **Ernesto: best-day record for item names** 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. Query parameters: - `locationId` (required) string - `itemNames` (required) string - `from` (required) string - `to` (required) string Responses: - `200` — Best day record #### `GET /operations/orders/item-sales` **Get aggregated specific item sales (range/month best year)** Gets aggregated item sales from Transactions:V2 for items whose name matches the provided `itemName` (case-insensitive substring). - With both `from` and `to` dates (YYYY-MM-DD): returns sales for the date range (createdAt, totalSales, totalItems, bestYear). - Without `from` and `to`: compares the current month across all years and returns the best year for that month. Requires authentication: use API key with "API " prefix, e.g. API Pk-XXXxxxxxxXXXXXXX-xxXX-xXXXXX Query parameters: - `locationId` (required) string — Location identifier to scope the item sales. - `itemName` (required) string — Substring to match in `order.items.name` (case-insensitive). Example: "combo", "burger", etc. - `from` string — Start date (YYYY-MM-DD). Required if `to` is provided. - `to` string — End date (YYYY-MM-DD). Required if `from` is provided. Responses: - `200` — Aggregated specific item sales for the best performing year/day: { createdAt, totalSales, totalItems, bestYear } - `403` — Forbidden - Authentication required #### `GET /operations/orders/kanban` **Real-time kanban window of recent orders** 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. Query parameters: - `locationsIds` (required) string[] — Locations to include in the kanban view - `from` string — Optional start of a historical window (ISO 8601). Requires `to`. - `to` string — Optional end of a historical window (ISO 8601). Requires `from`. Responses: - `200` — Kanban window payload #### `GET /operations/orders/kanban/stats` **Aggregate stats for the kanban view** 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. Query parameters: - `locationsIds` (required) string[] — Locations to scope the stats to - `from` (required) string — Start of the analysis window (ISO 8601) - `to` (required) string — End of the analysis window (ISO 8601) Responses: - `200` — Aggregated kanban stats #### `GET /operations/orders/kanban/stats/timeseries` **Per-day timeseries of the kanban stats** 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. Query parameters: - `locationsIds` (required) string[] — Locations to scope the timeseries to - `from` (required) string — Start of the analysis window (ISO 8601) - `to` (required) string — End of the analysis window (ISO 8601) Responses: - `200` — Per-day kanban stats #### `GET /operations/orders/live-operations` **Per-location live operations rollup** 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. Query parameters: - `locationsIds` (required) string[] — Locations to include (one row per location is returned) - `kpiWindow` string — KPI aggregation window. "last60m" (default) or "today" (start-of-day in each location timezone). Ignored when from/to are supplied. - `from` string — Optional explicit window start (ISO 8601); with `to`, overrides kpiWindow. - `to` string — Optional explicit window end (ISO 8601). Requires `from`. Responses: - `200` — Per-location live operations payload #### `GET /operations/orders/prep-time-stats` **Fetch prep-time statistics** Returns average / p50 / p95 order preparation times for the given locations and time window. Used by operations dashboards. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate prep-time stats for - `from` (required) string — Start of the analysis window (ISO 8601) - `to` (required) string — End of the analysis window (ISO 8601) - `source` string — Filter by origin source/channel - `serviceType` string — Filter by service type Responses: - `200` — Prep-time statistics ### Orders:Device:V2 #### `GET /operations/orders/device/v2` **List orders from a device (v2)** 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. Query parameters: - `state` string[] — Lifecycle states to include - `stationId` string — Station identifier to restrict results to Responses: - `200` — Orders visible to the device #### `PATCH /operations/orders/device/v2` **Update order state from a device (v2)** 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. Request body: `UpdateOrderState` Responses: - `200` — Order state updated #### `GET /operations/orders/device/v2/by-id` **Fetch an order by id from a device (v2)** 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. Query parameters: - `id` (required) string — Order identifier to fetch Responses: - `200` — Order details #### `PATCH /operations/orders/device/v2/item-ready` **Toggle the ready flag on one order slot from a device (v2)** One slot, same rule as the batch route: the flag lands in the calling station's overlay, never on the shared flags. Request body: `UpdateOrderItemReady` Responses: - `200` — Ready flag updated #### `PATCH /operations/orders/device/v2/items-ready` **Toggle ready flags on multiple order slots from a device (v2)** 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. Request body: `UpdateOrderItemsReady` Responses: - `200` — Ready flags updated #### `PATCH /operations/orders/device/v2/station-complete` **Record or clear one station completion of an order** 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. Request body: `SetStationCompleted` Responses: - `200` — Stamp result ### Payments #### `GET /operations/payments` **Fetch total payments by location** Returns payment totals grouped by location for the given time window. Covers every tender type (cash, card, online). Query parameters: - `to` (required) string — End of the window (ISO 8601) - `from` (required) string — Start of the window (ISO 8601) Responses: - `200` — Totals grouped by location #### `GET /operations/payments/by-hour` **Fetch cash payments by hour** Aggregates cash payment totals per hour of day within the window, for the requested locations. Used for cash-handling reports. Query parameters: - `locationsIds` (required) string[] — Locations to aggregate analytics for Responses: - `200` — Cash payment totals per hour ### Preferences #### `GET /operations/preferences/channel-groups` **Fetch the caller channel-groups preference** Returns the caller channel-groups preference, scoped per company. Falls back to an empty preference when none has been stored yet. Responses: - `200` `ChannelGroupsPreferenceResponse` — Channel groups preference for the caller #### `PUT /operations/preferences/channel-groups` **Upsert the caller channel-groups preference** Replaces the full preference document for the caller in the active company. Request body: `UpdateChannelGroupsPreference` Responses: - `200` `ChannelGroupsPreferenceResponse` — Persisted channel groups preference ### Releases #### `GET /operations/releases/latest` **Fetch the newest published build for an app** Called by a device to decide whether to install a newer APK over itself. Returns null when nothing is published for the applicationId + channel. Query parameters: - `applicationId` (required) string — Android applicationId the calling device is running - `channel` string — Release channel, defaults to production Responses: - `200` — The newest release, or null ### Reviews #### `GET /operations/reviews` **Fetch reviews** Returns every review (Google, in-house) received at the given locations during the time window. Query parameters: - `locationsIds` (required) string[] — Locations to fetch reviews for Responses: - `200` — Reviews for the locations #### `GET /operations/reviews/dashboard` **Fetch reviews for the dashboard** Returns the aggregated reviews view (totals, average rating, breakdown by rating) for the dashboard. Query parameters: - `locationsIds` (required) string[] — Locations to fetch reviews for Responses: - `200` — Aggregated review metrics ### Reviews:V2 #### `GET /operations/reviews/v2` **Fetch reviews (v2)** v2 reviews endpoint which uses the new reviews collection (more sources, consolidated schema). Query parameters: - `locationsIds` (required) string[] — Locations to fetch reviews for Responses: - `200` — Reviews for the locations #### `GET /operations/reviews/v2/dashboard` **Fetch reviews for the dashboard (v2)** v2 aggregated reviews view for dashboards (totals, averages, rating breakdown, source breakdown). Query parameters: - `locationsIds` (required) string[] — Locations to fetch reviews for Responses: - `200` — Aggregated review metrics ### Roles #### `GET /operations/members/roles` **List roles** Returns roles belonging to the caller company, optionally filtered by location ids. Responses: - `200` — Roles visible to the caller #### `POST /operations/members/roles` **Create a role** Creates a new role for the active company and locations. Request body: `Role` Responses: - `200` — Created role #### `PATCH /operations/members/roles` **Update a role** Partial update of a role record. Request body: `UpdateRole` Responses: - `200` — Updated role #### `DELETE /operations/members/roles` **Delete a role** Deactivates a role. Fails when members are still assigned to it. Query parameters: - `id` (required) string Responses: - `200` — Deletion result #### `GET /operations/members/roles/one` **Fetch a role by id** Returns the full role document for the given id. Query parameters: - `id` (required) string Responses: - `200` — Role details ### Schedules #### `POST /operations/schedules` **Create a schedule** Creates a schedule that activates menus, offers or devices at specific weekly time windows. Request body: `CreateSchedule` Responses: - `200` — Created schedule #### `PATCH /operations/schedules` **Update a schedule** Partial update of a schedule owned by the caller company. Request body: `UpdateSchedule` Responses: - `200` — Updated schedule #### `DELETE /operations/schedules` **Delete a schedule** Removes the schedule owned by the caller company. Query parameters: - `id` (required) string Responses: - `200` — Deletion result #### `GET /operations/schedules/by-company` **List schedules for the active company** Returns every schedule configured for the caller company across all locations. Responses: - `200` — Schedules for the company #### `GET /operations/schedules/by-menu` **List schedules targeting a menu** Returns every schedule that activates the given menu id, optionally scoped to a location/company. Query parameters: - `menuId` (required) string — Menu id whose schedules should be returned - `locationId` string — Location id to scope the query to - `companyId` string — Company id to scope the query to Responses: - `200` — Schedules for the menu #### `GET /operations/schedules/device` **Fetch schedules for a device** Returns the schedules active on the calling device, optionally filtered by type. Query parameters: - `type` string — Schedule type filter (MENU, OFFER, DEVICE, etc.) Responses: - `200` — Schedules for the device #### `GET /operations/schedules/device/versions` **Fetch menu versions for a device** Lightweight list of { menuId, version } for the menus active on the calling device. Clients poll this to detect stale menus. Query parameters: - `type` string — Schedule type filter (MENU, OFFER, DEVICE, etc.) Responses: - `200` — Menu versions for the device #### `GET /operations/schedules/endpoint` **Fetch schedules for an endpoint** Returns the schedules applicable to an endpoint session for a given location (and optional type). Query parameters: - `type` string — Schedule type filter (MENU, OFFER, DEVICE, etc.) - `locationId` (required) string — Location id to fetch schedules for Responses: - `200` — Schedules for the endpoint #### `GET /operations/schedules/endpoint/web` **Fetch web endpoint schedules** Returns schedules for the web-specific variant of the endpoint (different rendering constraints than in-app). Query parameters: - `type` string — Schedule type filter (MENU, OFFER, DEVICE, etc.) - `locationId` (required) string — Location id to fetch schedules for Responses: - `200` — Schedules for the web endpoint #### `GET /operations/schedules/endpoint/web/versions` **Fetch web endpoint menu versions** Lightweight list of { menuId, version } for the menus of a web endpoint. Clients poll this to detect stale menus. Query parameters: - `type` string — Schedule type filter (MENU, OFFER, DEVICE, etc.) - `locationId` (required) string — Location id to fetch schedules for Responses: - `200` — Menu versions for the web endpoint ### Shifts #### `POST /operations/shifts` **Create a shift for the current company** Request body: `CreateShiftDto` Responses: - `201` #### `GET /operations/shifts` **Fetch shifts for the current company** Query parameters: - `userType` string - `fleetId` (required) string Responses: - `200` #### `GET /operations/shifts/{shiftId}` **Fetch a single shift by id** Path parameters: - `shiftId` (string) Responses: - `200` #### `PATCH /operations/shifts/{shiftId}` **Update a shift** Path parameters: - `shiftId` (string) Request body: `UpdateShiftDto` Responses: - `200` #### `DELETE /operations/shifts/{shiftId}` **Delete (soft) a shift** Path parameters: - `shiftId` (string) Responses: - `200` #### `POST /operations/shifts/{shiftId}/overrides` **Create or upsert a date override for a shift** Path parameters: - `shiftId` (string) Request body: `CreateShiftOverrideDto` Responses: - `201` #### `GET /operations/shifts/{shiftId}/overrides` **Fetch date overrides for a shift** Path parameters: - `shiftId` (string) Query parameters: - `from` string — YYYY-MM-DD - `to` string — YYYY-MM-DD - `userId` string Responses: - `200` #### `PATCH /operations/shifts/{shiftId}/overrides/{overrideId}` **Update a shift date override** Path parameters: - `shiftId` (string) - `overrideId` (string) Request body: `UpdateShiftOverrideDto` Responses: - `200` #### `DELETE /operations/shifts/{shiftId}/overrides/{overrideId}` **Delete a shift date override** Path parameters: - `shiftId` (string) - `overrideId` (string) Responses: - `200` #### `GET /operations/shifts/{shiftId}/resolve` **Resolve a shift to a day-by-day expansion over a date range** Path parameters: - `shiftId` (string) Query parameters: - `from` (required) string — YYYY-MM-DD - `to` (required) string — YYYY-MM-DD - `userId` string Responses: - `200` #### `POST /operations/shifts/absences` **Create an absence** Request body: `CreateShiftAbsenceDto` Responses: - `201` #### `GET /operations/shifts/absences` **Fetch absences for the current company** Query parameters: - `userId` string - `userType` string - `from` string — YYYY-MM-DD - `to` string — YYYY-MM-DD Responses: - `200` #### `PATCH /operations/shifts/absences/{absenceId}` **Update an absence** Path parameters: - `absenceId` (string) Request body: `UpdateShiftAbsenceDto` Responses: - `200` #### `DELETE /operations/shifts/absences/{absenceId}` **Delete an absence** Path parameters: - `absenceId` (string) Responses: - `200` #### `GET /operations/shifts/by-user/{userId}` **Fetch shifts assigned to a user** Path parameters: - `userId` (string) Query parameters: - `userType` (required) string Responses: - `200` #### `GET /operations/shifts/requests` **Fetch absence requests for the current company** Query parameters: - `to` string — YYYY-MM-DD - `from` string — YYYY-MM-DD - `userType` string - `status` string Responses: - `200` #### `PATCH /operations/shifts/requests/{requestId}` **Approve or reject an absence request** Path parameters: - `requestId` (string) Request body: `DecideRequestDto` Responses: - `200` #### `GET /operations/shifts/requests/count` **Count absence requests matching the filter** Returns only the number of matching requests. Same filter as the list endpoint, for callers that render a count and never the rows. Query parameters: - `to` string — YYYY-MM-DD - `from` string — YYYY-MM-DD - `userType` string - `status` string Responses: - `200` #### `GET /operations/shifts/requests/paged` **List a page of absence requests with the matching total** 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. Query parameters: - `limit` string - `skip` string - `to` string — YYYY-MM-DD - `from` string — YYYY-MM-DD - `userType` string - `status` string Responses: - `200` #### `GET /operations/shifts/resolve` **Resolve all shifts for a date range (bulk)** Query parameters: - `from` (required) string — YYYY-MM-DD - `to` (required) string — YYYY-MM-DD - `userType` string - `fleetId` string Responses: - `200` #### `POST /operations/shifts/templates` **Create a shift template for the current company** Request body: `CreateShiftTemplateDto` Responses: - `201` #### `GET /operations/shifts/templates` **Fetch shift templates for the current company** Query parameters: - `archived` string — Include archived (visible:false) templates Responses: - `200` #### `PATCH /operations/shifts/templates/{templateId}` **Update a shift template** Path parameters: - `templateId` (string) Request body: `UpdateShiftTemplateDto` Responses: - `200` #### `DELETE /operations/shifts/templates/{templateId}` **Archive a shift template (default), or purge it permanently with ?purge=true when unused** Path parameters: - `templateId` (string) Query parameters: - `purge` string — Permanently delete (only allowed when usage is 0) Responses: - `200` #### `POST /operations/shifts/templates/{templateId}/restore` **Restore an archived shift template** Path parameters: - `templateId` (string) Responses: - `201` #### `GET /operations/shifts/templates/{templateId}/usage` **List user IDs whose shifts reference this template** Path parameters: - `templateId` (string) Responses: - `200` ### Stations flows #### `GET /operations/stations-flows` **Fetch the stations flows configured for the company** One flow per location. Locations without a flow simply have no document and behave as legacy (no routing). Query parameters: - `locationsIds` array — Optional location scope Responses: - `200` #### `PUT /operations/stations-flows` **Create or replace the stations flow of a location** 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. Query parameters: - `locationId` (required) string — Location whose flow is being configured Request body: `UpsertStationsFlow` Responses: - `200` #### `DELETE /operations/stations-flows` **Delete the stations flow of a location** The location reverts to legacy behavior (no routing) for new orders; in-flight flow orders complete normally. Query parameters: - `locationId` (required) string — Location whose flow is being removed Responses: - `200` #### `GET /operations/stations-flows/device` **Fetch the stations flow for the calling device location** Returns the flow document for the device session location, or null when the location has no flow configured. Responses: - `200` — Flow document or null ### Subscribers #### `GET /operations/subscribers` **List subscribers (paginated)** Returns newsletter/marketing subscribers for the active company, with optional text search, status filter and createdAt range. Query parameters: - `createdAtTo` string - `createdAtFrom` string - `status` string - `search` string - `pageSize` string - `page` string Responses: - `200` — Paginated subscribers ### Tasks #### `POST /operations/tasks` **Create a recurring task** Creates a recurring operations task (checklist style) with optional inputs and workflow events. Request body: `CreateTask` Responses: - `200` — Created task #### `GET /operations/tasks` **List tasks for a location** Returns every active task for the given location. Accepts the location id as a raw query string. Query parameters: - `locationId` string Responses: - `200` — Tasks at the location #### `PATCH /operations/tasks` **Update a task** Partial update of a task (title, inputs, cooldown, active/visible flags). Request body: `UpdateTask` Responses: - `200` — Updated task #### `DELETE /operations/tasks` **Delete a task** Permanently removes a task from the location. Request body: `TaskId` Responses: - `200` — Deletion result #### `GET /operations/tasks/device` **List tasks for the calling device member** Returns tasks active at the location bound to the calling member/device session. Responses: - `200` — Tasks for the member location ### Tasks:Done #### `GET /operations/tasks/done` **List task completions** Returns task completion records filtered by task/location with pagination. Query parameters: - `taskId` (required) string — Task template id - `locationId` string — Location id to filter by - `skip` string — Number of records to skip (pagination) - `limit` string — Maximum number of records to return (pagination) Responses: - `200` — Task completion records #### `PATCH /operations/tasks/done` **Update a task completion** Partial update for a task completion record (e.g. correct an input value). Request body: `object` Responses: - `200` — Updated completion #### `POST /operations/tasks/done/device` **Record a task completion from a device** Member-from-device endpoint to submit a completed task with its input responses and optional evidence. Request body: `CreateTaskDone` Responses: - `200` — Stored task completion record #### `GET /operations/tasks/done/device` **List task completions for the calling device** Returns completions filed by members operating on the calling device, scoped to the device location. Query parameters: - `taskId` (required) string — Task template id - `locationId` string — Location id to filter by - `skip` string — Number of records to skip (pagination) - `limit` string — Maximum number of records to return (pagination) Responses: - `200` — Task completion records #### `GET /operations/tasks/done/done-today` **List today's completions for a task** Returns the task completion records filed today at the calling member location for the given task id. Query parameters: - `id` (required) string Responses: - `200` — Today's completions #### `GET /operations/tasks/done/location` **List task completions at the member location** Returns completions filed at the calling member location for the given task id, paginated. Query parameters: - `id` (required) string - `skip` (required) number - `limit` (required) number Responses: - `200` — Task completion records #### `POST /operations/tasks/done/push-response` **Push an async response for a task** Used to append asynchronous results (e.g. an uploaded image URL that was processed later) to an existing task completion. Request body: `object` Responses: - `200` — Response appended ### User roles #### `GET /operations/users/roles` **List dashboard user roles** 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. Responses: - `200` — Roles in the company #### `POST /operations/users/roles` **Create a dashboard user role** Route paths are stored as given; unknown paths are harmless (they simply match no page) but a renamed route silently stops being granted. Request body: `UserRole` Responses: - `200` — The created role #### `PATCH /operations/users/roles` **Update a dashboard user role** Partial update. `permissions` and `locationIds` each replace their whole list — send the full set, not a delta. Request body: `UpdateUserRole` Responses: - `200` — The updated role #### `DELETE /operations/users/roles` **Delete a dashboard user role** Soft delete. Refused with 400 while any user still holds the role, because detaching it would silently widen their access to everything. Request body: `object` Responses: - `200` — Deletion result #### `GET /operations/users/roles/one` **Read one dashboard user role** Query parameters: - `id` (required) string Responses: - `200` — The role ### Users #### `GET /operations/users` **List users for the active company** Returns every user that belongs to the caller active company (and its sub-companies where applicable). Responses: - `200` — Users in the active company #### `PATCH /operations/users` **Update a user** 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. Request body: `object` Responses: - `200` — Updated user #### `DELETE /operations/users` **Delete a user** Disables a user (soft delete: active and visible are cleared). The caller may only delete a user ranked strictly below them. Request body: `object` Responses: - `200` — Deletion result #### `PATCH /operations/users/activate` **Activate a user** Marks a user as active so they can sign in to the dashboard. The caller may only activate a user ranked strictly below them. Request body: `object` Responses: - `200` — Activation result #### `POST /operations/users/complete-invite` **Complete an invite** Public endpoint that finalizes an invitation: sets the password for the invited user and activates their account. Request body: `object` Responses: - `200` — Activated user session #### `POST /operations/users/invite` **Invite a user** 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). Request body: `InviteUser` Responses: - `200` — Invitation dispatched #### `PATCH /operations/users/me` **Update the signed-in user own profile** Self-service partial update of the caller own name, phone and avatar. The target is always the session user; it never accepts a userId. Request body: `UpdateOwnUser` Responses: - `200` — Profile updated #### `GET /operations/users/me/notifications` **Read the signed-in user email notification preferences** Missing preferences resolve to enabled, so a user who never touched them gets both switches on. Responses: - `200` — Notification preferences #### `PATCH /operations/users/me/notifications` **Update the signed-in user email notification preferences** Accepts a partial payload; omitted channels keep their value. Request body: `UpdateOwnNotifications` Responses: - `200` — Preferences updated #### `POST /operations/users/me/password` **Change the signed-in user own password** Requires the current password. Returns reason currentPasswordInvalid (401) or weakPassword (400) on failure. Request body: `ChangeOwnPassword` Responses: - `200` — Password changed #### `POST /operations/users/resend-invite` **Resend a user invitation** Resends the invitation email for an existing (not yet activated) user. Useful when the original email expired. Request body: `object` Responses: - `200` — Invitation dispatched #### `POST /operations/users/update-password` **Update a user password** Public endpoint that finalizes a password recovery flow: validates the temp id and sets the new password. Request body: `object` Responses: - `200` — Password updated #### `POST /operations/users/validate-invite` **Validate an invite key** Public endpoint that checks whether an invitation key (from an invitation email) is still valid and returns its payload. Request body: `object` Responses: - `200` — Invite validation result ### operations schemas #### `AdvanceOrderStation` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Order to move along its SEQUENTIAL stations-flow route | | `direction` | `string` | no | FORWARD (default) moves the ticket to the next station of its route; BACK recalls it to the previous one (undo). | #### `AttachedLanPeripheral` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `host` | `string` | yes | LAN host (IP) | | `port` | `number` | yes | LAN port | #### `AttachedUsbPeripheral` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `vendorIdentifier` | `number` | yes | USB vendor identifier | | `productIdentifier` | `number` | yes | USB product identifier | #### `AuditImageStateDTO` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `tag` | `string` | yes | How the image is being provided | | `base64` | `string` | yes | Base64-encoded image payload (when tag is "base64") | | `extension` | `string` | yes | File extension of the image | | `contentType` | `string` | yes | MIME content type of the image | | `URL` | `string` | no | Absolute image URL (when tag is "URL") | #### `BulkGridUpdate` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationsIds` | `string[]` | yes | Locations whose device settings should receive the grid update | | `grid` | `string[]` | yes | Grid cells to apply (items, meals, groups, sections) | | `settingsIds` | `string[]` | no | Specific settings documents to target (otherwise all matching locations) | #### `BulkUpdateRole` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `memberIds` | `string[]` | yes | Ids of the members whose role should be updated | | `roleId` | `string` | yes | Role identifier to assign to every selected member | | `role` | `string` | no | Role display name to assign (kept in sync with roleId) | #### `CancelDeliveryOrderDto` Type: `object` #### `ChangeOwnPassword` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `currentPassword` | `string` | yes | Current password | | `newPassword` | `string` | yes | New password | #### `ChannelGroupDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | User-visible group name | | `channels` | `string[]` | yes | Channel labels assigned to this group | #### `ChannelGroupsPreferenceResponse` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `enabled` | `boolean` | yes | | | `groups` | `ChannelGroupDto[]` | yes | | | `channelOrder` | `string[]` | yes | | #### `ClockByCodeDto` Type: `object` #### `ClockInDto` Type: `object` #### `ClockOutDto` Type: `object` #### `CreateAbsenceRequestDto` Type: `object` #### `CreateAppRelease` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `applicationId` | `string` | yes | Android applicationId of the binary this release upgrades | | `channel` | `string` | no | Release channel, matching the expo-updates channel baked into the build. Defaults to "production" when omitted. | | `versionName` | `string` | yes | Human-facing version name. Displayed, never compared. | | `versionCode` | `number` | yes | Android versionCode. Devices install this release when it is strictly greater than their own native build version. | | `url` | `string` | yes | Direct download URL for the APK | | `notes` | `string` | no | Release notes shown to the operator before installing | | `mandatory` | `boolean` | no | Reserved for a future forced-install path | #### `CreateAuditResponse` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `type` | `string` | yes | Audit type identifier (e.g. cleanliness, opening checklist) | | `draft` | `boolean` | no | Save as draft instead of submitting the audit | | `locationId` | `string` | yes | Location the audit was performed at | | `locationName` | `string` | no | Human-readable name of the location (denormalized) | | `items` | `ItemDTO[]` | yes | Answers submitted for each question of the audit type | #### `CreateBenefit` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Link between the benefit and the target item / meal / discount | | `price` | `object` | no | Price override when redeeming the benefit | | `override` | `object` | no | Per-benefit content overrides (name, description, image, modifiers) | | `settings` | `object` | yes | Redemption settings (auto-apply, quotas, time-of-day, scope) | | `tags` | `string[]` | no | Free-form tags attached to the benefit | #### `CreateClientCompany` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `businessName` | `string` | yes | Legal/business name of the client company | | `taxId` | `string` | no | Tax id (CIF/NIF) | | `country` | `string` | no | ISO country code | | `address` | `string` | no | Billing address line | | `city` | `string` | no | City | | `contactEmail` | `string` | no | Contact email | | `contactPhone` | `string` | no | Contact phone | #### `CreateColor` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Routing metadata linking the color palette to companies/locations | | `name` | `string` | yes | Display name of the color | | `hex` | `string` | yes | Hex color code | | `tags` | `string[]` | no | Free-form tags attached to the color | #### `CreateCompany` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | Primary owner email for the new company | | `country` | `string` | no | Country where the company operates | | `businessName` | `string` | yes | Legal business name of the company | | `taxId` | `string` | yes | Company tax identifier (CIF/NIF/VAT) | | `address` | `string` | yes | Billing street address | | `state` | `string` | yes | Billing state / region | | `city` | `string` | yes | Billing city | | `zipCode` | `string` | yes | Billing postal code | #### `CreateDeliveryOrderAddressDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `address` | `string` | yes | | | `city` | `string` | yes | | | `country` | `string` | yes | | | `coordinates` | `CreateDeliveryOrderCoordinatesDto` | yes | | | `comment` | `string` | no | | | `description` | `string` | no | | | `door` | `string` | no | | | `floor` | `string` | no | | | `formattedAddress` | `string` | no | | | `state` | `string` | no | | | `zipCode` | `string` | no | | #### `CreateDeliveryOrderContactDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | | | `phone` | `string` | no | | #### `CreateDeliveryOrderCoordinatesDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `latitude` | `number` | yes | | | `longitude` | `number` | yes | | #### `CreateDeliveryOrderDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location identifier (Locations._id) where the order is picked up | | `provider` | `string` | no | Delivery platform/provider (e.g. GLOVO, UBER) | | `pickUp` | `CreateDeliveryOrderStopDto` | yes | | | `delivery` | `CreateDeliveryOrderStopDto` | yes | | | `offer` | `CreateDeliveryOrderOfferDto` | yes | | | `items` | `CreateDeliveryOrderItemDto[]` | yes | | | `metadata` | `CreateDeliveryOrderMetadataDto` | no | | | `security` | `CreateDeliveryOrderSecurityDto` | no | | | `schedule` | `CreateDeliveryOrderScheduleDto` | no | | #### `CreateDeliveryOrderItemDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | | | `price` | `number` | yes | | | `quantity` | `number` | yes | | | `size` | `string` | no | | #### `CreateDeliveryOrderMetadataDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `category` | `string` | no | | | `orderReference` | `string` | no | | | `priority` | `string` | no | | #### `CreateDeliveryOrderOfferDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `description` | `string` | no | | | `amount` | `number` | yes | | | `currency` | `string` | yes | | #### `CreateDeliveryOrderScheduleDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `deliveryAt` | `string` | yes | Target delivery date and time (ISO 8601) | #### `CreateDeliveryOrderSecurityDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `requestPicture` | `boolean` | no | | | `requestQR` | `boolean` | no | | | `code` | `string` | no | | #### `CreateDeliveryOrderStopDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `note` | `string` | no | | | `contact` | `CreateDeliveryOrderContactDto` | no | | | `address` | `CreateDeliveryOrderAddressDto` | yes | | #### `CreateDevice` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `type` | `string` | yes | 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). | | `name` | `string` | no | Human friendly device name | | `description` | `string` | no | Optional description for the device | | `version` | `number` | no | 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. | | `trace` | `object` | yes | Routing/identity metadata for the device | | `net` | `object` | no | Network configuration for devices reachable over the LAN | | `metadata` | `object` | no | Optional printer metadata. For USB protocol, vendor/product identifiers are required so the client can match the bound USB device. | #### `CreateEndpoint` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Human readable endpoint name | | `domains` | `string[]` | yes | 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. | | `type` | `string` | no | Which frontend this endpoint backs. Absent means WEB, for compatibility with endpoints created before the field existed. | | `scopes` | `string[]` | no | Scope identifiers that restrict what this endpoint exposes | | `locationsIds` | `string[]` | no | Locations this endpoint can serve | | `settings` | `any` | yes | Branding and integration settings for the endpoint | #### `CreateIncidentDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `category` | `string` | yes | | | `description` | `string` | yes | | | `channel` | `string` | yes | | #### `CreateInvoice` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Customer legal or display name | | `taxId` | `string` | yes | Customer tax identifier (NIF/CIF/VAT) | | `address` | `string` | yes | Customer billing address | | `receiptId` | `string` | yes | Receipt id the invoice is generated from | | `date` | `string` | yes | Date the invoice was issued (ISO 8601) | | `recursive` | `boolean` | no | Whether to save the customer data for future recurring invoices | #### `CreateInvoiceV2` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `transactionId` | `string` | yes | Transaction id the invoice is generated from | | `name` | `string` | yes | Customer legal or display name | | `taxId` | `string` | yes | Customer tax identifier (NIF/CIF/VAT) | | `address` | `string` | yes | Customer billing address | | `email` | `string` | yes | Customer email to deliver the invoice to | | `phone` | `object` | yes | Customer phone number (split into prefix + local number) | #### `CreateLocation` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Location name | | `status` | `string` | yes | Operational status of the location | | `trace` | `object` | yes | Routing metadata: parent company, optional SKU and coordinates | | `settings` | `object` | no | Location settings (currency, timezone, address, branding) | | `knownAs` | `string[]` | no | External provider identifiers linked to this location | | `businessName` | `string` | yes | Legal business name for the location | #### `CreateLocationV2` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Location name | | `status` | `string` | yes | Operational status of the location | | `businessName` | `string` | yes | Legal business name for the location | | `skipSku` | `boolean` | no | Skip auto-generating a SKU for this location | | `trace` | `object` | yes | Routing metadata | | `settings` | `object` | no | Location settings (currency, timezone, address, branding, workdays) | | `knownAs` | `string[]` | no | External provider identifiers linked to this location | #### `CreateProgram` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Program display name | | `type` | `string` | yes | Program mechanic (stamps, points, tiered, etc.) | | `settings` | `any` | yes | Program mechanic settings | | `tags` | `string[]` | no | Free-form tags attached to the program | | `trace` | `object` | yes | Routing metadata | #### `createReward` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Routing metadata linking the reward to a program and target entity | | `override` | `object` | no | Content overrides for the reward (name, description, image, modifiers) | | `tags` | `string[]` | no | Free-form tags attached to the reward | #### `CreateSchedule` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Schedule name | | `locationId` | `string` | yes | Location this schedule applies to | | `days` | `object` | yes | Weekly time windows keyed by weekday (mon-sun) | | `type` | `string` | yes | Schedule type (MENU, OFFER, DEVICE, etc.) | | `destinationsIds` | `string[]` | yes | Entities this schedule applies to (e.g. menu ids) | | `sourcesIds` | `string[]` | yes | Source entities that trigger this schedule | #### `CreateShiftAbsenceDto` Type: `object` #### `CreateShiftDto` Type: `object` #### `CreateShiftOverrideDto` Type: `object` #### `CreateShiftTemplateDto` Type: `object` #### `CreateTask` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `title` | `string` | no | Task title | | `description` | `string` | no | Task description | | `cooldown` | `number` | yes | Cooldown (in seconds) before the task can be marked done again | | `image` | `string` | no | Illustrative image URL | | `trace` | `any` | yes | Routing metadata (location the task runs at) | | `inputs` | `InputDto[]` | no | Inputs the member has to fill when marking the task done | | `events` | `string[]` | no | Optional workflow events triggered after completion | #### `CreateTaskDone` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Unique identifier generated client-side (idempotency) | | `trace` | `object` | yes | Routing metadata pointing at the task template | | `response` | `object` | yes | Response body: member, input values and timestamp | | `cooldown` | `number` | yes | Cooldown (seconds) before the task can be completed again | | `createdAt` | `string` | yes | Completion timestamp | | `updatedAt` | `string` | yes | Last update timestamp | #### `CreateTemplate` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Routing metadata linking the template to a program and color | | `name` | `string` | yes | Template display name | | `google` | `object` | yes | Google Wallet visual + field configuration | | `apple` | `object` | yes | Apple Wallet visual + field configuration | | `tags` | `string[]` | yes | Free-form tags attached to the template | #### `CreateUser` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Company the user will be attached to | | `email` | `string` | yes | Email address of the new user | | `name` | `string` | yes | User full name | | `role` | `string` | yes | Role assigned to the user (Admin, Manager, Cashier, ...) | #### `Credentials` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | User's email address | | `password` | `string` | yes | User's password | #### `Customer` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `any` | yes | Customer id | | `taxId` | `string` | yes | Customer taxId | | `email` | `string` | yes | Customer email | | `phone` | `object` | yes | Customer phone | | `name` | `string` | yes | Customer name | | `lastname` | `string` | yes | Customer lastname | | `birthdate` | `string` | yes | Customer birth date | | `address` | `string` | yes | Customer address | | `loyaltyCustomerId` | `string` | no | Customer id in the external loyalty provider | #### `DecideRequestDto` Type: `object` #### `DeliveryLiveTimerColumnPair` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `soonMinutes` | `number` | yes | Minutes after column entry when the card starts shifting toward red. -1 disables the warning. | | `lateMinutes` | `number` | yes | Minutes after column entry when the card reaches full red. -1 disables. | #### `DeliveryLiveTimerColumns` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `enPreparacion` | `DeliveryLiveTimerColumnPair` | yes | | | `esperandoRecogida` | `DeliveryLiveTimerColumnPair` | yes | | | `enReparto` | `DeliveryLiveTimerColumnPair` | yes | | #### `DeliveryLiveTimers` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `enabled` | `boolean` | yes | Whether the visualization is active | | `showItemCountInline` | `boolean` | no | Whether the order id should be displayed alongside the count of non-meal items (e.g. "AB12 (3 items)"). | | `itemCountMode` | `string` | no | How to count items: "topLevel" treats every line as one item (meals included); "expandMeals" walks meal steps and counts inner items × meal quantity. | | `columns` | `DeliveryLiveTimerColumns` | yes | | #### `ExecAction` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `command` | `string` | yes | 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. | | `locationsIds` | `string[]` | no | Locations whose devices should receive the command | | `deviceId` | `string` | no | Specific device to target (overrides locationsIds) | #### `ExportInvoicesByEmail` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `invoiceIdentifiers` | `string[]` | yes | Invoice identifiers to include in the export | | `email` | `string` | yes | Email address that will receive the export | | `locale` | `string` | yes | Locale for the email copy (es / en) | #### `FetchCustomerByEmailPayload` Type: `object` #### `fetchOrderByIdV2` Type: `object` #### `FetchOrdersBetweenDates` Type: `object` #### `FetchPaymentFromTool` Type: `object` #### `Font` Type: `object` #### `InputDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Input name shown to the member | | `type` | `string` | yes | Input type | | `description` | `string` | no | Help text for the input | | `extension` | `string` | no | File extension for file-typed inputs | | `required` | `boolean` | yes | Whether the member must provide this input to complete the task | #### `InviteCourier` Type: `object` #### `InviteUser` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Invitee full name | | `email` | `string` | yes | Invitee email address | | `role` | `string` | yes | Role the invitee will assume once they accept | | `roleId` | `string` | no | Page-access profile id (users/roles). Optional. | | `locationIds` | `string[]` | no | 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. | | `companiesIds` | `string[]` | no | 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. | | `locale` | `string` | yes | Locale for the invitation email (es or en; falls back to es) | #### `ItemDTO` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `questionId` | `string` | yes | Question identifier within the audit type | | `question` | `string` | yes | Question text answered by the member | | `choice` | `string` | yes | Selected choice identifier or label | | `answer` | `object` | no | Free-form answer (string or structured object) | | `image` | `any` | no | Optional image attached to this response | #### `Maintenance` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `serviceName` | `string` | yes | Target service to run maintenance on | | `serviceModule` | `string` | no | Optional submodule to scope the maintenance to | | `actions` | `string[]` | yes | Maintenance actions to execute in order | | `options` | `object` | yes | Scheduling window and notification options | | `reason` | `string` | no | Reason for the maintenance (logged with the audit record) | #### `MarkOrderSeen` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Order rendered on the KDS screen for the first time | #### `Member` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Member first name | | `lastName` | `string` | yes | Member last name | | `image` | `string` | no | Avatar image URL | | `role` | `string` | no | Member role (Manager, Cashier, Chef...) | | `email` | `string` | no | Member email address | | `active` | `boolean` | no | Whether the member account is active | | `phone` | `object` | no | Member phone number (prefix + local number) | | `code` | `number` | yes | Numeric pin code the member uses to sign in on a device | | `roleId` | `string` | no | Identifier of the role assigned to the member | | `contractedHours` | `number` | no | Weekly contracted hours (Mon-Sun) used for shift planning | | `trace` | `object` | yes | Routing metadata (linked user, company, locations) | | `tags` | `string[]` | yes | Free-form tags attached to the member | | `knownAs` | `string[]` | yes | External provider identifiers linked to the member | #### `NotificationChannel` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `enabled` | `boolean` | no | | #### `ObjectId` Type: `object` #### `OnboardingProgressDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `version` | `number` | yes | Payload schema version | | `config` | `object` | yes | The onboarding answers collected so far | | `currentStep` | `string` | yes | Current wizard step | | `furthestReachedIndex` | `number` | yes | Furthest step index the user has reached | | `completedAt` | `string` | yes | ISO completion timestamp, or null while in progress | #### `OrderItem` Type: `object` #### `OrderItemReadyChange` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `target` | `string` | yes | Which slot of the order is being toggled. Determines which other indices are required. | | `itemIndex` | `number` | yes | Index of the item inside Order.items | | `stepIndex` | `number` | no | Index of the meal step inside items[itemIndex].steps. Required for MEAL_STEP and MEAL_STEP_MODIFIER. | | `modifierIndex` | `number` | no | Index of the modifier. Required for ITEM_MODIFIER and MEAL_STEP_MODIFIER. | | `ready` | `boolean` | yes | Desired ready value. The change is idempotent. | #### `OrderPipeline` Type: `object` #### `OwnPhone` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `prefix` | `string` | no | Dial code | | `number` | `string` | no | National number, without the dial code | #### `PeripheralOffline` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `usb` | `any` | no | USB peripheral identifiers (set when a USB device was detached) | | `lan` | `any` | no | LAN peripheral identifiers (set when a LAN device went unreachable) | #### `PeripheralOfflineLan` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `host` | `string` | yes | LAN host of the peripheral that was just detached | | `port` | `number` | yes | LAN port of the peripheral that was just detached | #### `PeripheralOfflineUsb` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `vendorIdentifier` | `number` | yes | USB vendor identifier of the peripheral that was just detached | | `productIdentifier` | `number` | yes | USB product identifier of the peripheral that was just detached | #### `PostHeartbeat` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `appVersion` | `string` | no | App (Platomico) version running on the device | | `nativeBuildVersion` | `string` | no | 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. | | `updateId` | `string` | no | 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. | | `osVersion` | `string` | no | Operating system version of the device | | `platform` | `string` | no | Platform identifier for the device | | `batteryLevel` | `number` | no | 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%. | | `batteryState` | `string` | no | Battery state at the time of the beat. Mirrors expo-battery BatteryState by name. | | `attachedUsb` | `AttachedUsbPeripheral[]` | no | USB peripherals (printers / cash drawers) currently attached to this device. Used by the server to bump connectivity on the matching peripheral records. | | `attachedLan` | `AttachedLanPeripheral[]` | no | 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. | #### `Radius` Type: `object` #### `ReassignCourierDto` Type: `object` #### `Role` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Role display name | | `type` | `string` | yes | Role type / category slug | | `permissions` | `string[]` | yes | Permission strings granted by the role | | `active` | `boolean` | no | Whether the role can currently be assigned / used | | `visible` | `boolean` | no | Whether the role is shown in selection lists | | `isSystem` | `boolean` | no | Whether the role was seeded from the default catalog (system role) | | `trace` | `object` | yes | Routing metadata (company, locations) | #### `SeedOnboardingInvite` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Existing os company id to onboard (deal.clientCompanyIdentifier) | | `locale` | `string` | no | | | `owner` | `SeedOnboardingInviteOwner` | yes | | | `prefill` | `SeedOnboardingInvitePrefill` | no | | #### `SeedOnboardingInviteOwner` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | | | `email` | `string` | yes | | #### `SeedOnboardingInvitePrefill` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `businessName` | `string` | no | | #### `ServiceStatus` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `serviceName` | `string` | yes | Target service whose status is being updated or queried | #### `SetStationCompleted` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Order identifier to stamp | | `stationId` | `string` | no | 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. | | `completed` | `boolean` | no | true stamps the completion, false clears it (undo). Defaults to true. | #### `Settings` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Settings document name | | `type` | `string` | yes | Settings type (e.g. POS., KDS., KIOSK.) | | `logo` | `string` | no | Logo URL used in the device UI | | `font` | `any` | no | Font preferences | | `customFonts` | `string[]` | no | 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. | | `theme` | `any` | yes | Theme (colors) | | `terminal` | `any` | yes | Terminal / payment settings | | `radius` | `any` | yes | Border radius presets | | `ui` | `any` | yes | Layout + grid definition | | `settings` | `object` | no | Extended configuration (accepted tenders, channels, features, links) | | `trace` | `object` | yes | Routing metadata | | `knownAs` | `string[]` | no | External provider identifiers linked to this settings doc | | `kdsFilter` | `object` | no | 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. | #### `StampsSettings` Type: `object` #### `TaskId` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Task identifier | #### `Terminal` Type: `object` #### `Theme` Type: `object` #### `Trace` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location the task runs at | #### `TraceDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location the task runs at | #### `UI` Type: `object` #### `UpdateAutoPrintDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationIds` | `string[]` | yes | Locations to apply the auto-print settings to | | `autoPrint` | `object` | yes | Orders that must NOT print automatically. Both lists are deny lists: absent or empty means every order auto-prints. | #### `UpdateChannelGroupsPreference` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `enabled` | `boolean` | yes | Whether grouping is currently enabled | | `groups` | `ChannelGroupDto[]` | yes | Custom channel groups | | `channelOrder` | `string[]` | yes | Channel display order (drag-reorderable in the drawer) | #### `UpdateClientCompany` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | os company id to update (deal.clientCompanyIdentifier) | | `businessName` | `string` | no | | | `taxId` | `string` | no | | | `country` | `string` | no | | | `address` | `string` | no | | | `city` | `string` | no | | | `contactEmail` | `string` | no | | | `contactPhone` | `string` | no | | #### `UpdateCourierConfigurationDto` Type: `object` #### `UpdateCourierLocationsDto` Type: `object` #### `UpdateDeliveryLiveTimersDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location to update | | `timers` | `DeliveryLiveTimers` | yes | | #### `UpdateDevice` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `deviceId` | `string` | yes | Device identifier to update | | `name` | `string` | no | New display name for the device | | `description` | `string` | no | Updated description for the device | | `status` | `string` | no | Lifecycle status for the device | | `version` | `number` | no | Device contract version. v2 devices use the new transport-aware dispatch (OPEN_CASH_DRAWER, USB / LAN_ANDROID transports). | | `trace` | `object` | no | Partial routing/identity metadata overrides. For PRINTER devices, printRouting sets per-pickup-type print routing (fail-open when absent). | | `net` | `object` | no | Partial network configuration overrides | | `metadata` | `object` | no | Partial printer metadata overrides | | `knownAs` | `object` | no | External provider identifiers linked to the device | #### `UpdateDevicePreferences` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `deviceId` | `string` | no | 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. | | `preferences` | `object` | yes | 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. | #### `UpdateEndpoint` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | Human readable endpoint name | | `type` | `string` | no | 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. | | `locationsIds` | `string[]` | no | Locations this endpoint serves. ["*"] means every location of the company. | #### `UpdateEndpointDomains` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `domains` | `string[]` | yes | 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. | | `type` | `string` | no | 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. | #### `UpdateEndpointSettings` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `ui` | `object` | no | Element-level style overrides. Shallow-merged into the existing `ui`, so a caller that sends only `override` keeps `pageThemes` and `itemPalettes` intact. | | `logo` | `string` | no | Brand logo URL | | `icon` | `string` | no | Favicon URL | | `seo` | `object` | no | SEO metadata for the storefront. Editing it purges the 4h `endpoint-seo-*` cache. | | `online` | `object` | no | Online payment provider. Editing it purges the 4h `endpoint-provider-*` cache. | | `theme` | `any` | no | Brand palette | | `font` | `any` | no | Font slots | | `radius` | `any` | no | Corner radii | | `customFonts` | `string[]` | no | The KEPT list of company-uploaded fonts. Assigned wholesale, so omitting an entry deletes it; new files travel in `fontFiles`. | | `image` | `object` | no | A new logo as base64. Uploaded to S3 and stored as `settings.logo`; the caller cannot reach the bucket itself. | | `fontFiles` | `string[]` | no | Font files as base64. Uploaded to S3 and appended to `customFonts`, replacing any entry with the same `family`. | | `uiImages` | `string[]` | no | 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. | #### `UpdateIncidentDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `status` | `string` | no | | | `priority` | `string` | no | | #### `UpdateMember` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Member id | | `name` | `string` | no | Updated first name | | `lastName` | `string` | no | Updated last name | | `image` | `string` | no | Updated avatar URL | | `role` | `string` | no | Updated role | | `email` | `string` | no | Updated email address | | `active` | `boolean` | no | Updated active state | | `roleId` | `string` | no | Updated role identifier | | `phone` | `object` | no | Updated phone number | | `code` | `number` | no | Updated 4-digit pin (0–9999) used to sign in on a device | | `contractedHours` | `number` | no | Updated weekly contracted hours (Mon-Sun) | | `locationsIds` | `string[]` | no | Updated accessible locations; ["*"] grants all locations | #### `UpdateOrder` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Order identifier to update | | `state` | `string` | no | New state for the order | | `priority` | `number` | yes | Display priority (lower = shown first) | | `type` | `string` | yes | Fulfillment channel | | `customer` | `object` | no | Customer details attached to the order | | `delivery` | `object` | no | Delivery details (required when type is DELIVERY) | | `items` | `OrderItem[]` | yes | Updated line items for the order | #### `UpdateOrderDeliveryId` Type: `object` #### `UpdateOrderDeliveryStatus` Type: `object` #### `UpdateOrderItemReady` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Order identifier whose item ready flag is being updated | | `target` | `string` | yes | Which slot of the order is being toggled. Determines which other indices are required. | | `itemIndex` | `number` | yes | Index of the item inside Order.items | | `stepIndex` | `number` | no | Index of the meal step inside items[itemIndex].steps. Required for MEAL_STEP and MEAL_STEP_MODIFIER. | | `modifierIndex` | `number` | no | Index of the modifier. Required for ITEM_MODIFIER and MEAL_STEP_MODIFIER. | | `ready` | `boolean` | yes | Desired ready value. The call is idempotent. | #### `UpdateOrderItemsReady` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Order identifier whose item ready flags are being updated | | `changes` | `OrderItemReadyChange[]` | yes | Batch of ready-flag changes applied to the order in a single atomic write. | #### `UpdateOrderState` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Order identifier to update | | `state` | `string` | yes | New order state | #### `UpdateOwnNotifications` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `closingSummary` | `NotificationChannel` | no | | | `lowStock` | `NotificationChannel` | no | | #### `UpdateOwnUser` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | Updated full name | | `phone` | `any` | no | Updated phone, split so the dial code never counts towards the national number length | | `avatar` | `string` | no | Updated avatar URL | #### `UpdatePerformanceThresholdDto` Type: `object` #### `UpdatePosDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationIds` | `string[]` | yes | Locations to apply the POS settings to | | `pos` | `object` | yes | 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). | #### `UpdateRole` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Role id | | `name` | `string` | no | Updated name | | `type` | `string` | no | Updated type | | `permissions` | `string[]` | no | Updated permission strings | | `active` | `boolean` | no | Updated active state | | `visible` | `boolean` | no | Updated visibility | #### `UpdateSchedule` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | no | Schedule id to update | | `name` | `string` | no | Schedule name | | `locationId` | `string` | no | Location this schedule applies to | | `days` | `object` | no | Weekly time windows keyed by weekday (mon-sun) | | `type` | `string` | no | Schedule type (MENU, OFFER, DEVICE, etc.) | | `destinationsIds` | `string[]` | no | Entities this schedule applies to (e.g. menu ids) | | `sourcesIds` | `string[]` | no | Source entities that trigger this schedule | #### `UpdateSettings` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `image` | `object` | no | New logo/image to upload as a base64 + extension tuple | | `color` | `string` | no | Primary brand color as a hex string | | `name` | `string` | no | Company display name | | `type` | `string` | no | Company business type (e.g. RESTAURANT, RETAIL) | | `billing` | `object` | no | Billing information to update | | `settings` | `object` | no | 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. | #### `UpdateShiftAbsenceDto` Type: `object` #### `UpdateShiftDto` Type: `object` #### `UpdateShiftOverrideDto` Type: `object` #### `UpdateShiftTemplateDto` Type: `object` #### `UpdateStatus` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `accountId` | `string` | yes | Provider account id to identify the company | | `status` | `string` | yes | New onboarding status for the company | #### `UpdateSupportRequestStatusDto` Type: `object` #### `UpdateTask` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Task identifier | | `trace` | `any` | yes | Routing metadata | | `title` | `string` | no | Updated title | | `description` | `string` | no | Updated description | | `cooldown` | `boolean` | no | Updated cooldown in seconds | | `image` | `string` | no | Updated image URL | | `visibl` | `boolean` | no | Toggle task visibility | | `active` | `boolean` | no | Toggle task active state | | `inputs` | `InputDto[]` | no | Updated inputs | | `events` | `string[]` | no | Updated events | #### `UpdateTicketsDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationIds` | `string[]` | yes | Locations to apply the ticket settings to | | `tickets` | `object` | yes | Ticket printing flags | #### `UpdateUserRole` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | | | `name` | `string` | no | | | `permissions` | `string[]` | no | | | `locationIds` | `string[]` | no | Replaces the whole location list. Send `[]` to widen the role back to every location. | | `active` | `boolean` | no | | | `visible` | `boolean` | no | | #### `UpdateWorkdaysDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationIds` | `string[]` | yes | Locations to apply the workdays schedule to | | `workdays` | `object` | yes | 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). | | `days` | `string[]` | no | 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. | #### `UpsertStationsFlow` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `mode` | `string` | yes | 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. | | `enabled` | `boolean` | yes | Disabled flows are kept but ignored: order routing behaves exactly as if no flow existed. | | `stations` | `string[]` | yes | 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. | #### `UserRole` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Display name of the role | | `permissions` | `string[]` | yes | Route paths this role may open. Anything not listed is hidden and blocked. | | `locationIds` | `string[]` | no | 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. | | `active` | `boolean` | no | | | `visible` | `boolean` | no | | #### `VerifyPhone` Type: `object` --- ## payments Transactions, discounts, taxes, payouts, cash registers. Base path: `/payments` · scope name: `payments` ### Cash #### `GET /payments/cash-registers` **List cash registers for the caller** Returns the cash registers visible to the caller, optionally filtered by one or more location ids. Query parameters: - `locationsIds` string — One or more location ids (repeat the parameter for multiple values) Responses: - `200` — List of cash registers #### `POST /payments/cash-registers` **Create a cash register** Registers a new cash register for the given location and attaches it to one or more devices. Request body: `CreateCashRegister` Responses: - `200` — Created cash register record #### `GET /payments/cash-registers/balance` **Get the current cash balance** Returns the expected cash amount currently in the drawer for the specified register. Query parameters: - `registerId` (required) string Responses: - `200` — Current cash balance #### `POST /payments/cash-registers/close` **Close the cash register shift** Closes the current shift, records the final counted cash, and produces a snapshot with any over/short difference. Request body: `CloseCashRegister` Responses: - `200` — Closed snapshot record #### `GET /payments/cash-registers/device` **Fetch the cash register bound to the caller device** Returns the single cash register the calling device is attached to (if any). Responses: - `200` — Cash register bound to the device #### `POST /payments/cash-registers/open` **Open the cash register for a shift** Records the starting float and marks the cash register open for the calling member. Request body: `OpenCashRegister` Responses: - `200` — Opened snapshot record #### `GET /payments/cash-registers/snapshots` **List cash register snapshots** Returns the closing snapshots (shifts) recorded for the caller locations over a date range, paginated. Query parameters: - `locationsIds` (required) string - `limit` (required) string - `skip` (required) string - `to` (required) string - `from` (required) string Responses: - `200` — Paginated list of snapshots #### `PUT /payments/cash-registers/snapshots/{id}` **Update a snapshot** Replaces the fields of an existing snapshot (amounts, descriptions, nested breakdowns). Path parameters: - `id` (string) Request body: `UpdateCashSnapshot` Responses: - `200` — Updated snapshot #### `POST /payments/cash-registers/snapshots/{id}/fix` **Record a correction for a snapshot** Registers an out-of-band fix to a snapshot (e.g. note explaining a difference) and optionally notifies staff. Path parameters: - `id` (string) Request body: `CreateSnapshotFix` Responses: - `200` — Fix applied to the snapshot #### `GET /payments/cash-registers/snapshots/export` **Export a snapshot as CSV** Streams a CSV export of the specified snapshot (contents: cash movements + summary). Query parameters: - `id` (required) string Responses: - `200` — CSV file download #### `GET /payments/cash-registers/snapshots/fetchById` **Fetch a snapshot by id** Returns a single cash register snapshot with the full breakdown of openings, sales, refunds, etc. Query parameters: - `id` (required) string Responses: - `200` — Snapshot details #### `GET /payments/cash-registers/snapshots/paged` **List a page of cash register snapshots with the matching total** 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. Query parameters: - `locationsIds` (required) string - `limit` string - `skip` string - `to` (required) string - `from` (required) string Responses: - `200` — A page of snapshots and the total matching the filter #### `POST /payments/cash-registers/track` **Track a cash movement** Records a single cash movement (sale, refund, income, outcome, change, etc.) against the caller cash register. Request body: `TrackCashRegisterTransaction` Responses: - `200` — Recorded cash transaction #### `GET /payments/cash-registers/transactions` **List cash register transactions** Returns cash movements recorded for the caller register, paginated by skip/limit. Query parameters: - `skip` string — Number of records to skip (pagination offset) - `limit` string — Maximum number of records to return Responses: - `200` — Paginated list of cash transactions #### `GET /payments/cash-registers/transactions/by-range` **List cash transactions for a device and date range** Returns cash movements recorded by a specific device over an ISO date range. Query parameters: - `deviceId` (required) string - `from` (required) string - `to` (required) string Responses: - `200` — List of cash transactions in the range #### `GET /payments/cash-registers/transactions/current` **List cash transactions for the current open shift of a register** 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. Query parameters: - `registerId` (required) string — Id of the cash register whose current (open) shift transactions should be returned - `skip` string — Number of records to skip (pagination offset) - `limit` string — Maximum number of records to return Responses: - `200` — Current shift transactions and summary ### Cash:Charges #### `POST /payments/cash-machines/charges` **Start a cash-machine charge (does not wait)** 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. Request body: `CreateCashChargeRequest` Responses: - `200` `CashChargeView` #### `GET /payments/cash-machines/charges/{cashChargeId}` **Poll a cash charge** Returns status, how much the customer has inserted so far, and the outcome once settled. Cheap and idempotent — safe to call every second. Path parameters: - `cashChargeId` (string) Responses: - `200` `CashChargeView` #### `POST /payments/cash-machines/charges/{cashChargeId}/cancel` **Cancel a cash charge** 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. Path parameters: - `cashChargeId` (string) Responses: - `200` `CashChargeView` ### Cash:Deposits #### `POST /payments/cash-machines/deposits` **Start a cash-machine deposit (does not wait)** 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. Request body: `CreateCashDepositRequest` Responses: - `200` `CashDepositView` #### `GET /payments/cash-machines/deposits/{cashDepositId}` **Poll a cash deposit** Returns status, how much has been inserted so far, and the outcome once settled. Cheap and idempotent — safe to call every second. Path parameters: - `cashDepositId` (string) Responses: - `200` `CashDepositView` #### `POST /payments/cash-machines/deposits/{cashDepositId}/cancel` **Cancel a cash deposit** 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. Path parameters: - `cashDepositId` (string) Responses: - `200` `CashDepositView` ### Cash:Machines #### `POST /payments/cash-jobs/{jobId}/claim` **Claim a cash job before driving the machine** Moves the job from PENDING to RUNNING. Returns claimed:false when another poller got there first — the caller must then not touch the machine. Path parameters: - `jobId` (string) Responses: - `200` #### `POST /payments/cash-jobs/{jobId}/progress` **Report how much cash the customer has inserted so far** 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. Path parameters: - `jobId` (string) Request body: `CashChargeProgress` Responses: - `200` #### `POST /payments/cash-jobs/{jobId}/result` **Report what the cash machine did** 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. Path parameters: - `jobId` (string) Request body: `PostCashJobResult` Responses: - `200` #### `GET /payments/cash-jobs/{jobId}/state` **Is this job still mine to run?** 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. Path parameters: - `jobId` (string) Responses: - `200` #### `POST /payments/cash-jobs/cancel-active` **Abort the cash operation this device currently has running** 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. Responses: - `200` #### `POST /payments/cash-jobs/inventory` **Report what the cash machine is holding** 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. Request body: `ReportCashInventoryRequest` Responses: - `200` #### `GET /payments/cash-jobs/pending` **List cash jobs waiting for this device** Polled by the till as a fallback for a dropped SSE connection. Returns only PENDING jobs addressed to the calling device. Responses: - `200` — Pending cash jobs #### `GET /payments/cash-machines/inventory` **Cash held by the machines at a location** 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. Query parameters: - `locationId` string — Defaults to the session's location Responses: - `200` `CashMachineInventoryView[]` ### Cash:Withdrawals #### `POST /payments/cash-machines/withdrawals` **Start a cash-machine withdrawal (does not wait)** 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. Request body: `CreateCashWithdrawalRequest` Responses: - `200` `CashWithdrawalView` #### `GET /payments/cash-machines/withdrawals/{cashWithdrawalId}` **Poll a cash withdrawal** Returns status and the outcome once settled. Cheap and idempotent — safe to call every second. Path parameters: - `cashWithdrawalId` (string) Responses: - `200` `CashWithdrawalView` #### `POST /payments/cash-machines/withdrawals/{cashWithdrawalId}/cancel` **Cancel a cash withdrawal** 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. Path parameters: - `cashWithdrawalId` (string) Responses: - `200` `CashWithdrawalView` ### Discounts #### `POST /payments/discounts` **Create a discount** Creates a new discount (percentage or fixed) with an optional set of redemption codes. Request body: `CreateDiscount` Responses: - `200` — Created discount record #### `GET /payments/discounts` **List active discounts** Returns the active discounts for the given locations filtered by the caller source (POS, kiosk, etc.). Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — List of active discount records #### `PATCH /payments/discounts/{id}` **Update a discount** Partially updates a discount (amount, scope, codes, etc.). Path parameters: - `id` (string) Request body: `UpdateDiscount` Responses: - `200` — Updated discount record #### `DELETE /payments/discounts/{id}` **Delete a discount** Permanently removes a discount from the company. Path parameters: - `id` (string) Responses: - `200` — Deletion result #### `GET /payments/discounts/all` **List all discounts (including inactive)** Returns every discount configured for the given locations, including inactive/archived ones. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — List of discount records #### `GET /payments/discounts/by-id/{id}` **Fetch a discount by id** Returns a single discount scoped to the session location, if applicable. Path parameters: - `id` (string) Query parameters: - `orderAmount` string — Current pre-discount cart total in cents; enables the minimum-order check (F6). Responses: - `200` — Discount record #### `GET /payments/discounts/device` **Fetch discounts for a device** Returns discounts resolved for the device session, optionally filtered by a specific set of ids. Query parameters: - `discountsIds` (required) string[] — Discount ids to fetch - `loyaltyCustomerId` (required) string Responses: - `200` — List of discount records #### `GET /payments/discounts/device/count` **Count discounts visible from a device** Returns the number of discounts available for the device session. Useful to show a badge in the POS. Query parameters: - `loyaltyCustomerId` (required) string Responses: - `200` — Number of discounts #### `GET /payments/discounts/with-code` **Find a discount by redemption code** Used by checkout to resolve a customer-entered discount code to a discount record. Query parameters: - `code` (required) string - `locationId` string - `orderAmount` string — Current pre-discount cart total in cents; enables the minimum-order check (F6). Responses: - `200` — Matching discount record or null if not found ### Fees #### `POST /payments/fees` **Create a fee rule** Registers a new fee (e.g. delivery commission, service fee) that applies to transactions matching its location and provider scope. Request body: `CreateFee` Responses: - `200` — Created fee record #### `GET /payments/fees` **List fees for locations** Returns the fees configured for the given locations within the caller company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — List of fee records #### `PATCH /payments/fees` **Update a fee rule** Replaces the stored values for an existing fee record (amount, scope, provider). Request body: `UpdateFee` Responses: - `200` — Updated fee record ### Health #### `GET /payments/health` **Service health check** Returns the health status of the payments service and its dependencies. Used by uptime probes and orchestrators. Responses: - `200` — Health details per subsystem ### Payments #### `POST /payments/in-person` **Process an in-person card payment (legacy)** Legacy single-step in-person card payment. Charges the reader paired to the calling device. Prefer the v2 endpoint for new integrations. Request body: `Order` Responses: - `200` — Transaction and payment result #### `DELETE /payments/in-person` **Cancel an in-flight in-person payment (legacy)** Cancels the pending in-person payment currently attached to the calling device. Responses: - `200` — Cancellation result #### `POST /payments/in-person/splitted` **Process a single leg of a split in-person payment (legacy)** Charges one leg (card/cash portion) of a previously tokenised split payment. Request body: `Order` Responses: - `200` — Per-leg transaction result #### `POST /payments/in-person/splitted/refund` **Refund a split in-person payment (legacy)** Refunds a split in-person payment leg or the full operation. Request body: `Order` Responses: - `200` — Refund result #### `POST /payments/in-person/splitted/token` **Create a token for a split in-person payment (legacy)** Creates a token for a split payment (multiple cards/cash) that will be finalised in subsequent steps. Request body: `Order` Responses: - `200` — Token reference #### `POST /payments/in-person/token` **Create a token for an in-person payment (legacy)** Creates an intent/token for a card payment that will be finalised in a separate step (useful to split UI flows). Request body: `Order` Responses: - `200` — Token reference #### `POST /payments/in-person/with-cash` **Process an in-person cash payment (legacy)** Records an in-person cash payment and computes change based on the tendered amount. Request body: `Order` Responses: - `200` — Transaction result with change calculation #### `POST /payments/in-person/with-cash/intent` **Create an in-person cash payment intent (legacy)** Creates a cash payment intent that can be completed or cancelled later. Request body: `Order` Responses: - `200` — Cash payment intent #### `POST /payments/in-person/with-token` **Finalise an in-person payment using a token (legacy)** Processes an in-person payment using a token previously created via /in-person/token. Request body: `Order` Responses: - `200` — Transaction and payment result #### `POST /payments/online/intent` **Create an online payment intent (legacy)** Creates a Stripe/Revolut payment intent for an online endpoint session, which the frontend then confirms. Request body: `PaymentWithCard` Responses: - `200` — Payment intent client secret and metadata #### `POST /payments/online/validate-merchant` **Validate the merchant for Apple Pay (legacy)** Returns the Apple Pay merchant session payload required to bootstrap the browser's Payment Request. Request body: `ValidateMerchantPayload` Responses: - `200` — Apple Pay merchant session #### `POST /payments/online/with-card` **Process an online card payment (legacy)** Charges a card for an online endpoint session (ordering site / QR). Legacy flow. Request body: `PaymentWithCard` Responses: - `200` — Transaction and payment result ### Payments:Flows #### `GET /payments/flows` **List configured payment flows** Returns the payment flows (ordered step sequences) configured for the caller company. Responses: - `200` — List of flow records #### `POST /payments/flows` **Create a payment flow** Creates a new payment flow (a named list of steps executed in order to complete a checkout). Request body: `CreateFlow` Responses: - `200` — Created flow record #### `PATCH /payments/flows` **Update the current payment flow** Updates the flow associated with the caller session. Payload shape is derived from the session scope. Responses: - `200` — Updated flow record #### `DELETE /payments/flows` **Delete the current payment flow** Removes the flow associated with the caller session. Responses: - `200` — Deletion result ### Payments:OpenTables #### `POST /payments/v2/open-tables` **Open a table (DINE_IN, POS)** 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. Request body: `Order` Responses: - `200` — Id of the open-table transaction #### `POST /payments/v2/open-tables/{transactionId}/charge` **Charge an open table** 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. Path parameters: - `transactionId` (string) Request body: `Order` Responses: - `200` — Id of the completed transaction #### `POST /payments/v2/open-tables/{transactionId}/items` **Update an open table (sync items)** 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). Path parameters: - `transactionId` (string) Request body: `Order` Responses: - `200` — Sync result #### `POST /payments/v2/open-tables/{transactionId}/join` **Join another open bill into this one (juntar mesas)** 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). Path parameters: - `transactionId` (string) Responses: - `200` — Join result #### `POST /payments/v2/open-tables/{transactionId}/void` **Void an open table** Cancels an IN_PROGRESS open-table transaction and its KDS order. PIN/permission gating happens on the POS client. Path parameters: - `transactionId` (string) Responses: - `200` — Void result ### Payments:Sources #### `POST /payments/sources` **Create a payment source** Registers a new origin/channel (e.g. a delivery provider store) so transactions coming from it can be attributed to the company. Request body: `CreateSource` Responses: - `200` — Created source record ### Payments:V2 #### `POST /payments/v2/apple-pay/register-domain` **Register a domain for Apple Pay** Registers a web domain with Revolut so Apple Pay works on it. Domain must serve the Apple Pay verification file. Request body: `object` Responses: - `200` — Registered domain record #### `POST /payments/v2/in-person/custom` **Charge a custom amount (v2)** 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. Request body: `CustomCharge` Responses: - `200` — Transaction result #### `POST /payments/v2/in-person/intent` **Create an in-person payment intent (v2)** Creates a Stripe in-person payment intent for the given amount/currency. The device then presents the reader to complete the payment. Request body: `Charge` Responses: - `200` — Payment intent identifier #### `POST /payments/v2/in-person/with-card` **Process an in-person card payment (v2)** Creates a transaction and charges the reader paired to the calling member session. Runs the full v2 payment pipeline. Request body: `Order` Responses: - `200` — Transaction result #### `DELETE /payments/v2/in-person/with-card` **Cancel an in-flight in-person payment (v2)** Cancels the in-person card payment currently attached to the caller device. Responses: - `200` — Cancellation result #### `POST /payments/v2/in-person/with-card-manual` **Process an in-person manual card payment (v2)** 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. Request body: `Order` Responses: - `200` — Transaction result #### `POST /payments/v2/in-person/with-cash` **Process an in-person cash payment (v2)** Records an in-person cash payment via the v2 pipeline, computes change based on tendered amount, and persists the transaction. Request body: `Order` Responses: - `200` — Transaction result with change calculation #### `POST /payments/v2/online/intent` **Create an online payment intent (v2)** Creates a Stripe/Revolut payment intent for an online order that the frontend will then confirm. Request body: `Order` Responses: - `200` — Payment intent client secret and metadata #### `POST /payments/v2/online/token` **Create an online payment token (v2)** Tokenises an order so the online payment can be confirmed in a later step (e.g. once the customer chooses their method). Request body: `Order` Responses: - `200` — Token reference #### `POST /payments/v2/online/with-card` **Process an online card payment (v2)** Charges a card for an online order in one shot (no separate intent step). Used by server-side flows. Request body: `Order` Responses: - `200` — Transaction result ### Payments:V2:Loyalty #### `GET /payments/v2/loyalty/accrual` **Points a transaction has already earned** 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. Query parameters: - `transactionId` (required) string Responses: - `200` — Accrual state for the transaction #### `POST /payments/v2/loyalty/claim` **Claim the loyalty points for a transaction** 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. Request body: `ClaimLoyaltyPointsRequest` Responses: - `200` `ClaimLoyaltyPointsResponse` — Claim outcome #### `GET /payments/v2/loyalty/enabled` **Whether loyalty is enabled for a location** 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. Query parameters: - `locationId` string Responses: - `200` — Loyalty enablement #### `POST /payments/v2/loyalty/resolve` **Resolve a loyalty customer and their applicable promotions** 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. Request body: `ResolveLoyaltyRequest` Responses: - `200` — Loyalty resolution ### Platform #### `GET /payments/platform/connection-token` **Fetch a Stripe Terminal connection token** Returns a short-lived connection token used by the Stripe Terminal SDK to pair with a card reader. Responses: - `200` — Connection token #### `GET /payments/platform/refresh` **Refresh the provider onboarding link (redirect target)** Landing URL Stripe/Revolut redirects to when an onboarding link expires. Issues a new onboarding link and redirects there. Query parameters: - `id` (required) string — Stripe connected account id Responses: - `200` — Redirect response to a fresh onboarding link #### `GET /payments/platform/success` **Complete provider onboarding (redirect target)** Landing URL Stripe/Revolut redirects to after a successful onboarding flow. Finalises the account and redirects the user back to the app. Query parameters: - `id` (required) string — Stripe connected account id Responses: - `200` — Redirect response to the onboarding success page ### Split Payments #### `POST /payments/v2/split/leg` **Append a leg (AMOUNT-mode only)** Appends a new PENDING leg to an AMOUNT-mode session. Rejects if the new sum would exceed the bill total. Request body: `AppendLeg` Responses: - `200` — Updated session and the new leg #### `POST /payments/v2/split/leg/{identifier}/charge` **Charge a single leg** 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. Path parameters: - `identifier` (string) Request body: `ChargeLeg` Responses: - `200` — Updated session and the charged leg #### `POST /payments/v2/split/session` **Create a split-payment session** 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. Request body: `CreateSplitSession` Responses: - `200` — Created session #### `GET /payments/v2/split/session` **Resume a split-payment session by token** Verifies the JWT token and returns the latest session state from the database. Query parameters: - `token` (required) string Responses: - `200` — Resumed session #### `POST /payments/v2/split/session/abort` **Abort a split session** Marks the session FAILED. Refunds COMPLETED CARD legs through their gateway. CASH/CARD_MANUAL legs are marked REFUNDED for manual reversal. Request body: `AbortSession` Responses: - `200` — Aborted session with refunded legs #### `POST /payments/v2/split/session/finalize` **Finalize a fully-paid split session** Runs the post-payment pipeline (verify legs, build bill, push to KDS, track consumption, create transaction) and returns the resulting transaction id. Request body: `FinalizeSession` Responses: - `200` — Finalized session and the transaction id ### Subscribers #### `POST /payments/subscribers` **Create a subscriber** Attaches the calling customer to a subscription program/template by completing a provider (Stripe/Ayden) checkout session. Request body: `SubscriberPayload` Responses: - `200` — Created subscriber record plus provider references #### `GET /payments/subscribers/customer` **List subscriptions of the current customer** Returns the subscriptions attached to the calling customer session, optionally scoped by subscription id. Query parameters: - `sid` string Responses: - `200` — List of subscriber records for the customer ### Subscriptions #### `POST /payments/subscriptions` **Create a subscription product** Registers a new subscription offering (with price tiers and provider) for the caller company. Request body: `SubscriptionPayload` Responses: - `200` — Created subscription product #### `GET /payments/subscriptions` **List subscription products for an endpoint** Returns the subscription products available at the caller endpoint (ordering site, QR, etc.). Responses: - `200` — List of subscription products #### `GET /payments/subscriptions/fetchById` **Fetch a subscription product by id** Returns a single subscription product scoped to the caller company. Query parameters: - `id` (required) string Responses: - `200` — Subscription product #### `POST /payments/subscriptions/stripe/portal` **Create a Stripe customer portal session** Returns a URL to the Stripe-hosted customer portal where the customer can manage their subscription. Request body: `CustomerPortal` Responses: - `200` — Customer portal URL #### `POST /payments/subscriptions/stripe/session` **Create a Stripe checkout session for a subscription** Starts a Stripe-hosted checkout session so the customer can buy a subscription. Request body: `SubscriptionSession` Responses: - `200` — Stripe checkout session URL and id ### Tables #### `GET /payments/v2/tables` **List the location tables** 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. Responses: - `200` — Tables with occupancy state #### `POST /payments/v2/tables` **Create a table** Request body: `CreateTable` Responses: - `200` — Created table #### `PATCH /payments/v2/tables/{tableId}` **Update a table** Rename, change zone/seats, or archive (active: false). Archiving is rejected with 409 while the table is occupied. Path parameters: - `tableId` (string) Request body: `UpdateTable` Responses: - `200` — Update result ### Taxes #### `POST /payments/taxes` **Create a tax rule** Registers a new tax (e.g. VAT) that will be applied to transactions matching its location scope. Request body: `CreateTax` Responses: - `200` — Created tax record #### `GET /payments/taxes` **List taxes for locations** Returns the taxes configured for the given locations within the caller company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — List of tax records #### `PATCH /payments/taxes` **Update a tax rule** Partially updates an existing tax record (amount, scope, name, etc.). Request body: `UpdateTax` Responses: - `200` — Updated tax record ### Transactions #### `GET /payments/transactions` **List transactions (legacy)** Legacy transactions listing endpoint. Prefer /transactions/v2 for new integrations. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — List of transactions for the date range #### `GET /payments/transactions/endpoint` **Fetch a transaction from an endpoint (legacy)** Returns a transaction for a customer-facing endpoint (QR, ordering). Lookup by transaction id or order id. Query parameters: - `tid` string - `oid` string Responses: - `200` — Transaction details ### Transactions:Payouts #### `GET /payments/payouts` **Collect payouts across gateways (JIT)** 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. Query parameters: - `providers` string — Comma-separated gateways to collect from. Defaults to all payout-capable gateways. - `from` string — Lower bound on payout creation time (ISO 8601) - `to` string — Upper bound on payout creation time (ISO 8601) - `currency` string — Filter by ISO 4217 currency code - `limit` number — Maximum payouts to collect per gateway (1-100) Responses: - `200` `CollectPayoutsResult` ### Transactions:V2 #### `GET /payments/transactions/v2` **List transactions (v2)** 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. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. Responses: - `200` — The matching transactions #### `GET /payments/transactions/v2/by-id` **Fetch a transaction by id** 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. Query parameters: - `transactionId` (required) string Responses: - `200` — Transaction details #### `GET /payments/transactions/v2/dashboard/statistics` **Fetch dashboard statistics bundle** Returns the consolidated dashboard statistics for the caller company over the filter window. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. Responses: - `200` — Dashboard statistics bundle #### `GET /payments/transactions/v2/endpoint` **Fetch a transaction from an endpoint** Returns a transaction for a customer-facing endpoint (QR, ordering). Used to render the post-payment screen. Query parameters: - `tid` string Responses: - `200` — Transaction details for the endpoint #### `POST /payments/transactions/v2/endpoint/review` **Submit a review from an endpoint** Attaches a rating/comment left by the customer to a transaction (used by post-payment review screens). Request body: `CreateReview` Responses: - `200` — Created review record #### `GET /payments/transactions/v2/export` **Export transactions as CSV** Streams a CSV export of the transactions matching the provided filter. One row per transaction. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. Responses: - `200` — CSV file download #### `GET /payments/transactions/v2/invoice-link` **Fetch an invoice link for a transaction** Returns a download/share link for the PDF invoice of the given transaction. Query parameters: - `tid` string Responses: - `200` — Invoice link #### `GET /payments/transactions/v2/order-sequence` **Peek the next daily order sequence number for this device** 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. Responses: - `200` — The next sequence number (0-99), not yet consumed #### `GET /payments/transactions/v2/paged` **List transactions with their total (v2)** 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. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. Responses: - `200` — A page of transactions and the total matching the filter #### `POST /payments/transactions/v2/print` **Print a transaction receipt** Sends a print job to a receiver/printer for the given transaction. Supports different templates. Request body: `PrintReceiptDto` Responses: - `200` — Print job acknowledgement #### `POST /payments/transactions/v2/print/push` **Push a transaction receipt to a specific device** Queues one or more print templates for the given transaction onto the specified target printer. Authenticated as a device. Request body: `PushPrintDto` Responses: - `200` — Print job acknowledgement with the list of queued templates #### `GET /payments/transactions/v2/receipt-image` **Render a transaction receipt as PNG** Renders the receipt for the given transaction as a PNG image (used for chat/email previews). Query parameters: - `tid` (required) string - `template` string Responses: - `200` — PNG image of the receipt #### `POST /payments/transactions/v2/refund` **Refund a transaction** Issues a refund (full or partial) against a payment of the caller company. Records the member or email of the requester. Request body: `RefundPayloadV2` Responses: - `200` — Refund result #### `GET /payments/transactions/v2/statistics` **Fetch transaction statistics** Returns aggregate transaction statistics (counts, amounts) for the caller device and filter window. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Aggregate statistics #### `GET /payments/transactions/v2/statistics/dashboard` **Fetch the dashboard statistics bundle** Returns the consolidated statistics bundle used by the Platomico admin dashboard (sales, counts, rankings). Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Dashboard statistics bundle #### `GET /payments/transactions/v2/statistics/device` **Fetch transaction statistics for the calling device** Returns aggregate transaction statistics scoped to the calling device session (e.g. per-POS dashboard). Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Aggregate statistics for the device #### `GET /payments/transactions/v2/statistics/finance-close` **Fetch the financial close report** Returns the structured financial close report bundled by channel group, provider, category and VAT rate. Drives the analytics finance-close PDF/XLSX export. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Financial close report #### `GET /payments/transactions/v2/statistics/items` **Fetch top-selling items** Returns aggregate sales statistics grouped by item id, sorted descending by revenue. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Statistics grouped by item #### `GET /payments/transactions/v2/statistics/items-sold` **Fetch units sold per item and combo** 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). Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Counts per item/combo #### `GET /payments/transactions/v2/statistics/items-sold/by-source` **Fetch units sold per item, combo and modifier, grouped by source** 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. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Counts per item/combo id, keyed by source #### `GET /payments/transactions/v2/statistics/sales` **Fetch sales statistics** Returns aggregate sales statistics (net/gross, discounts, taxes, fees) for the filter window. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Sales totals #### `GET /payments/transactions/v2/statistics/sales/by-location` **Fetch sales statistics grouped by location and day** 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. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Sales totals per location per day #### `GET /payments/transactions/v2/statistics/service-type` **Fetch transaction statistics broken down by service type** Returns aggregate transaction statistics grouped by service type (DINE_IN, TAKE_AWAY, DELIVERY). Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Statistics grouped by service type #### `GET /payments/transactions/v2/statistics/source` **Fetch transaction statistics broken down by source** Returns aggregate transaction statistics grouped by source/channel (POS, KIOSK, ORDERING, etc.). Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Statistics grouped by source #### `GET /payments/transactions/v2/statistics/source/bundle` **Fetch transaction statistics by source bundle** Returns transaction statistics grouped by an aggregated source bundle (e.g. "delivery providers" combines Glovo+UberEats). Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Statistics grouped by source bundle #### `GET /payments/transactions/v2/statistics/source/bundle/v2` **Fetch transaction statistics by source bundle (v2)** V2 endpoint. Uses a single unified builder so Products + Services = Gross sales (ex-IVA), aligned with the financial report PDF. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Statistics grouped by source bundle (v2) #### `GET /payments/transactions/v2/statistics/source/service-type` **Fetch transaction statistics broken down by source and service type** Returns aggregate transaction statistics grouped by source and resolved service type (DINE_IN, TAKE_AWAY, DELIVERY), used for per-channel average ticket breakdowns. Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` — Statistics grouped by source and service type ### Transactions:V3 #### `GET /payments/transactions/v3` **List transactions (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics` **Fetch transaction statistics (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/finance-close` **Fetch finance close report (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/items` **Fetch top-selling items (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/items-sold/by-source` **Fetch units sold per item/combo by source (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/sales` **Fetch sales statistics (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/sales/by-location` **Fetch sales statistics by location and day (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/service-type` **Fetch statistics by service type (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/source` **Fetch statistics by source (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/source/bundle` **Fetch statistics by source bundle (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/source/bundle/v2` **Fetch statistics by source bundle v2 (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` #### `GET /payments/transactions/v3/statistics/source/service-type` **Fetch statistics by source and service type (time-of-day aware)** Query parameters: - `from` string — Start of date range (inclusive) - `to` string — End of date range (exclusive) - `locationsIds` string[] — Location ids to scope the query to - `timezone` string — IANA timezone used to bucket the results - `search` string — Free-text search term (matches receipt/customer/etc.) - `serviceType` string — Filter by service type - `source` string — Filter by origin source/channel - `paymentType` string — Filter by payment method - `paymentTypes` string[] — Filter by one or more payment methods (CASH, CARD, OTHER). Repeatable query parameter. - `granularity` string — Bucket the results by calendar period (day or month) in the given timezone. When omitted the range is returned as a single aggregate. - `status` string — Filter by transaction status (e.g. IN_PROGRESS for open tables). When omitted, IN_PROGRESS transactions are excluded. - `sortBy` string — Field to order by. Defaults to createdAt so an unsorted request keeps its existing order. - `sortDirection` string — Order direction. Defaults to DESC. - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. Responses: - `200` ### payments schemas #### `AbortSession` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `token` | `string` | yes | | | `reason` | `string` | no | | #### `AppendLeg` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `token` | `string` | yes | | | `amount` | `number` | yes | | | `currency` | `string` | yes | | #### `Benefit` Type: `object` #### `CashChargeProgress` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `insertedTotal` | `number` | yes | Cash inserted so far, in cents, as reported by the machine. | | `awaitingRemoval` | `boolean` | no | 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. | #### `CashChargeView` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `cashChargeId` | `string` | yes | Cash charge identifier, used to poll and to cancel | | `transactionId` | `string` | yes | Transaction the sale will be recorded under. Minted up front so the client knows it before the customer has paid. | | `status` | `string` | yes | PENDING (waiting for the till) · RUNNING (customer inserting) · SETTLING (recording the sale) · COMPLETED (paid and recorded) · FAILURE · EXPIRED · CANCELED | | `amount` | `number` | yes | Amount to collect, in cents | | `currency` | `string` | yes | Currency of the charge | | `insertedTotal` | `number` | yes | How much the customer has inserted so far, in cents. Progress only — the outcome always comes from the machine total on settlement. | | `receivedTotal` | `number` | no | Cash the machine took, in cents. Present once settled. | | `dispensedTotal` | `number` | no | Change the machine dispensed, in cents. Present once settled. | | `code` | `string` | no | Machine-readable failure code when the charge did not complete (device_error, not_ready, timeout, canceled, ...). | | `reason` | `string` | no | Operator-facing explanation, including the physical action needed when the machine is not ready. | | `needsReconciliation` | `boolean` | no | True when the machine took the money but the sale could not be recorded. Needs reconciliation — never shown as a clean success. | | `awaitingCashRemoval` | `boolean` | no | 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. | #### `CashDenomination` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `valueCents` | `number` | yes | Face value in cents | | `pieces` | `number` | yes | How many of them the machine holds | | `unit` | `number` | yes | 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. | #### `CashDepositView` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `cashDepositId` | `string` | yes | Cash deposit identifier, used to poll and to cancel | | `status` | `string` | yes | PENDING (waiting for the till) · RUNNING (operator feeding cash) · SETTLING (recording the movement) · COMPLETED (in the machine and recorded) · FAILURE · EXPIRED · CANCELED | | `amount` | `number` | yes | 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. | | `currency` | `string` | yes | Currency of the deposit | | `insertedTotal` | `number` | yes | How much has been inserted so far, in cents. Progress only. | | `receivedTotal` | `number` | no | Cash the machine took in, in cents. Present once settled. | | `dispensedTotal` | `number` | no | Change the machine dispensed back, in cents. Present once settled. The ledger movement books receivedTotal minus this — the net actually kept. | | `awaitingCashRemoval` | `boolean` | no | True while the machine is holding dispensed change and waiting for it to be taken. The deposit cannot finish until it is. | | `code` | `string` | no | Machine-readable failure code when the deposit did not complete (device_error, not_ready, timeout, canceled, unknown, ...). | | `reason` | `string` | no | Operator-facing explanation, including the physical action needed when the machine is not ready. | | `needsReconciliation` | `boolean` | no | True when the machine took the money but the register ledger could not be updated. Needs reconciliation — never shown as a clean success. | #### `CashMachineInventoryView` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `cashMachineId` | `string` | yes | | | `heldTotal` | `number` | yes | Total cash inside the machine, in cents | | `notesTotal` | `number` | yes | Of the held total, how much is in notes | | `coinsTotal` | `number` | yes | 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. | | `currency` | `string` | yes | | | `denominations` | `CashDenomination[]` | yes | Everything the machine holds, per denomination | | `inFlightTotal` | `number` | yes | Cash currently being collected or paid out by unfinished operations, in cents. Not part of the held total. | | `inFlightCount` | `number` | yes | How many operations that in-flight figure covers | | `reportedAt` | `string` | no | When the till last read the machine | | `stale` | `boolean` | yes | 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. | #### `CashWithdrawalView` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `cashWithdrawalId` | `string` | yes | Cash withdrawal identifier, used to poll and to cancel | | `status` | `string` | yes | PENDING (waiting for the till) · RUNNING (machine dispensing) · SETTLING (recording the movement) · COMPLETED (dispensed and recorded) · FAILURE · EXPIRED · CANCELED | | `amount` | `number` | yes | Amount the operator intends to withdraw, in integer cents | | `currency` | `string` | yes | Currency of the withdrawal | | `dispensedTotal` | `number` | no | Cash the machine actually paid out, in cents. Present once settled. | | `code` | `string` | no | Machine-readable failure code when the withdrawal did not complete (device_error, not_ready, timeout, canceled, unknown, ...). | | `reason` | `string` | no | Operator-facing explanation, including the physical action needed when the machine is not ready. | | `needsReconciliation` | `boolean` | no | True when the machine dispensed the cash but the register ledger could not be updated. Needs reconciliation — never shown as a clean success. | #### `Charge` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount to charge, in minor units (cents) | | `currency` | `string` | yes | ISO 4217 currency code | #### `ChargeLeg` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `token` | `string` | yes | | | `method` | `string` | yes | | | `tendered` | `number` | no | | #### `ClaimLoyaltyPointsRequest` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `transactionId` | `string` | yes | Transaction to credit. Must belong to the signed-in customer session company. | #### `ClaimLoyaltyPointsResponse` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `status` | `string` | yes | Outcome of the claim | | `points` | `number` | no | Points credited, when the provider reports a count. Square returns a delta; Comeback accrues on its own side and reports none. | | `enrolled` | `boolean` | no | Whether a loyalty account was created for this customer | #### `CloseCashRegister` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `description` | `string` | no | Optional note explaining the closing conditions | | `amount` | `number` | yes | Cash counted at close, in minor units (cents) | | `currency` | `string` | yes | ISO 4217 currency code | #### `CollectPayoutsResult` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `payouts` | `Payout[]` | yes | All payouts merged across gateways, newest first | | `sources` | `PayoutSourceResult[]` | yes | Per-gateway collection outcome. Fail-open: one gateway failing does not block the others. | #### `CreateAccount` Type: `object` #### `CreateCashChargeRequest` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount to collect, in integer cents | | `currency` | `string` | no | 3-letter ISO currency; must match the location currency | | `order` | `any` | no | The order to record once the cash is confirmed. Omit when charging a custom amount — the server builds the one-line order itself. | | `customAmount` | `object` | no | 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. | | `openTableTransactionId` | `string` | no | Open-table transaction to complete, when the cash settles an existing bill. Omit for a direct sale. | #### `CreateCashDepositRequest` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount the operator intends to deposit, in integer cents | | `currency` | `string` | no | 3-letter ISO currency; must match the location currency | | `description` | `string` | no | Optional note recorded on the resulting ledger movement | #### `CreateCashRegister` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Devices and location the cash register is bound to | #### `CreateCashWithdrawalRequest` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount the operator intends to withdraw, in integer cents | | `currency` | `string` | no | 3-letter ISO currency; must match the location currency | | `description` | `string` | no | Optional note recorded on the resulting ledger movement | #### `CreateDiscount` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Scope metadata describing where the discount applies | | `name` | `string` | yes | Human readable discount name | | `type` | `string` | no | Whether the discount is a percentage or a fixed amount | | `amount` | `number` | yes | Discount value; whole percent for PERCENT (e.g. 10 = 10%) or cents for FIXED (e.g. 1000 = 10.00) | | `codes` | `string[]` | no | List of redemption codes customers can enter to apply the discount | | `singleUse` | `boolean` | no | If true, each code can only be redeemed once per customer | | `appliesToBasePriceOnly` | `boolean` | no | 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). | | `appliesToSingleLine` | `boolean` | no | 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. | | `menusIds` | `string[]` | no | Restrict to specific menus by id | | `hidden` | `boolean` | no | If true, the discount is omitted from the browsable POS list but remains redeemable by code/QR. | | `validFrom` | `string` | no | ISO date/time from which the discount becomes valid. Omit for no start bound. | | `validUntil` | `string` | no | ISO date/time after which the discount expires. Omit for no expiry. | | `usageLimit` | `object` | no | Usage caps. interval is the calendar reset period (EVER = lifetime). maxGlobal caps total redemptions; maxPerMember caps redemptions per staff member. | | `minOrderAmount` | `number` | no | Minimum pre-discount order total (cents) required to redeem the discount. Omit for no minimum. | | `loyaltyCustomerId` | `string` | no | 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` | `string` | no | 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. | #### `CreateDomain` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Id of the company the domain should be registered for | | `locationId` | `string` | yes | Id of the location associated with the domain | | `accountId` | `string` | no | Optional Stripe/Revolut connected account id | | `domain` | `string` | no | Domain to register for Apple Pay/wallet use | #### `CreateFee` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Location scope and provider the fee applies to | | `name` | `string` | yes | Human readable fee name | | `description` | `string` | no | Optional description shown to merchants | | `type` | `string` | yes | Fee computation type: PERCENT (basis points) or FIXED (cents) | | `amount` | `number` | yes | Fee value; basis points for PERCENT (1000 = 10%) or cents for FIXED | | `min` | `number` | no | Optional minimum fee in cents | | `max` | `number` | no | Optional maximum fee cap in cents | #### `CreateFlow` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Human readable flow name | | `description` | `string` | no | Optional description of the flow | | `trace` | `object` | yes | Scope metadata (locations and sources this flow applies to) | | `useCase` | `string` | yes | Use case this flow is intended for | | `steps` | `Step[]` | yes | Ordered list of steps executed during the flow | #### `CreateLocation` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Id of the company the location belongs to | | `locationId` | `string` | yes | Id of the Platomico location to link | | `accountId` | `string` | no | Optional Stripe/Revolut connected account id | #### `CreateReader` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Id of the company the reader belongs to | | `locationId` | `string` | yes | Id of the location where the reader is physically installed | | `code` | `string` | yes | Pairing code printed on the card reader | | `accountId` | `string` | no | Optional Stripe/Revolut connected account id | #### `CreateReview` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `transactionId` | `string` | yes | Id of the transaction the review is attached to | | `rating` | `number` | no | Star rating (typically 1-5) | | `comment` | `string` | no | Free-form review text | #### `CreateSnapshotFix` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `description` | `string` | yes | Human readable reason for recording the fix | | `notifyAlert` | `boolean` | no | Whether to raise an alert notification to the company staff | #### `CreateSource` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `externalId` | `string` | yes | External identifier for the source (e.g. provider account id) | | `name` | `string` | yes | Human readable name of the source | #### `CreateSplitSession` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `bill` | `SplitSessionBill` | yes | | | `plan` | `CreateSplitSessionPlan` | yes | | | `source` | `string` | yes | | #### `CreateSplitSessionPlan` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `mode` | `string` | yes | | | `legs` | `CreateSplitSessionPlanLeg[]` | yes | | #### `CreateSplitSessionPlanLeg` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount in minor units (cents) | | `currency` | `string` | yes | | | `itemsIds` | `string[]` | no | | #### `CreateTable` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | | | `zone` | `string` | no | | | `seats` | `number` | no | | #### `CreateTax` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Scope metadata (locations and external tax/account ids) | | `name` | `string` | yes | Human readable tax name | | `description` | `string` | no | Optional description shown to merchants | | `currency` | `string` | yes | ISO 4217 currency code | | `type` | `string` | yes | Tax computation type: PERCENT (basis points) or FIXED (cents) | | `amount` | `number` | yes | Tax value; basis points for PERCENT (1000 = 10%) or cents for FIXED | | `min` | `number` | no | Optional minimum tax amount in cents | | `max` | `number` | no | Optional maximum tax cap in cents | | `default` | `boolean` | no | Marks this tax as the company default, applied to transactions created without item-level taxes (gateway webhooks, integrations) | #### `CreateTransactionV3Dto` Type: `object` #### `CreateWebhook` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Id of the company the webhook belongs to | | `events` | `string[]` | yes | Stripe event types the webhook should subscribe to | | `url` | `string` | yes | HTTPS URL Stripe should POST events to | #### `CustomCharge` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount to charge, in minor units (cents). Must be a positive integer — this is the exact figure the terminal will ask for | | `method` | `string` | yes | How the money is taken | | `label` | `string` | no | What the line reads on the ticket. Defaults to "Custom amount" when absent or blank | | `taxId` | `string` | no | Tax to apply. Omit to fall back to the company default tax; pass null to charge with no tax at all | | `tendered` | `number` | no | What the customer handed over, in minor units. CASH only — change is computed from it | | `note` | `string` | no | Free-form note carried to the kitchen ticket and the receipt | | `type` | `string` | no | Fulfillment type recorded on the sale | #### `CustomerPortal` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `returnUrl` | `string` | yes | URL the customer portal redirects back to after the session ends | | `customerId` | `string` | yes | Provider customer id to open the portal for | #### `ExternalPayload` Type: `object` #### `FetchStatus` Type: `object` #### `FinalizeSession` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `token` | `string` | yes | | #### `FixTransaction` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Id of the company whose transactions should be reconciled | | `from` | `string` | yes | Start of date range (ISO string) | | `to` | `string` | yes | End of date range (ISO string) | | `paymentId` | `string` | yes | Id of the payment to reconcile | | `source` | `string` | yes | Source/channel the transactions originated from | #### `FulfillTransaction` Type: `object` #### `FulFillTransactionDto` Type: `object` #### `Item` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Id of the parent order this item belongs to | | `hash` | `string` | yes | Deterministic hash of the item (id + modifiers) used for deduplication | | `type` | `string` | yes | 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 | | `id` | `string` | yes | Catalog item or meal id. A custom amount carries the CUSTOM_LINE_ID sentinel, so every one groups together in reporting instead of scattering | | `name` | `string` | no | Human readable item name (cached from catalog) | | `quantity` | `number` | yes | Number of units of this item | | `menuId` | `string` | no | 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. | | `modifiers` | `string[]` | yes | Selected modifiers with their quantities and optional prices | | `unitPrice` | `object` | no | Unit price before multiplying by quantity | | `price` | `object` | yes | Final line price (unitPrice * quantity + modifiers) | | `steps` | `string[]` | yes | Nested item steps (for meals composed of groups of items) | | `benefit` | `any` | no | Benefit (loyalty reward) applied to this line if any | | `note` | `string` | no | Free-form note attached to this line (e.g. for the kitchen) | | `taxes` | `string[]` | no | 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 | #### `LoyaltyCartLineDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `reference` | `string` | yes | | | `name` | `string` | yes | | | `quantity` | `number` | yes | | | `unitAmount` | `number` | yes | | #### `OpenCashRegister` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `description` | `string` | no | Optional note about the opening (e.g. shift, reason) | | `amount` | `number` | yes | Initial float placed in the drawer, in minor units (cents) | | `currency` | `string` | yes | ISO 4217 currency code | #### `Order` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | no | Trace metadata (pass attached, source channel, menu sold from) | | `type` | `string` | yes | Order fulfilment type | | `note` | `string` | no | Free-form note for the order (e.g. for the kitchen) | | `customer` | `object` | no | Customer contact info | | `pickup` | `object` | no | Scheduled pickup time (ISO timestamp plus human-readable format) | | `delivery` | `object` | no | Delivery details (only for DELIVERY orders) | | `payment` | `object` | no | Payment details (method, discounts, optional intent) | | `items` | `Item[]` | yes | Line items in the order | | `utils` | `object` | no | Utility fields used during processing | #### `OrderItem` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `orderId` | `string` | yes | Id of the parent order this item belongs to | | `hash` | `string` | yes | Deterministic hash of the item (id + modifiers) used for deduplication | | `type` | `string` | yes | Whether the row refers to a catalog item or a composed meal | | `id` | `string` | yes | Catalog item or meal id | | `quantity` | `number` | yes | Number of units of this item | | `modifiers` | `string[]` | yes | Selected modifiers with their quantities | | `price` | `object` | yes | Unit price of the item | | `steps` | `string[]` | yes | Nested item steps (for meals composed of groups of items) | #### `PaymentWithCard` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `order` | `any` | yes | Order being paid for | | `locationId` | `string` | yes | Location id where the payment is attributed | | `paymentStatus` | `string` | yes | Current state of the payment | | `paymentIntent` | `object` | no | Payment intent info when finalising a previously started intent | #### `Payout` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Provider-native payout identifier | | `provider` | `string` | yes | Gateway the payout was collected from | | `status` | `string` | yes | Normalized payout status | | `amount` | `number` | yes | Amount in the currency minor unit (e.g. cents) | | `currency` | `string` | yes | ISO 4217 currency code | | `createdAt` | `string` | yes | When the payout was created (ISO 8601) | | `arrivalDate` | `string` | no | Expected/known arrival date in the bank (ISO 8601) | | `destinationType` | `string` | no | Destination kind reported by the gateway | #### `PayoutSourceResult` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `provider` | `string` | yes | | | `ok` | `boolean` | yes | Whether the gateway was queried successfully | | `count` | `number` | yes | Number of payouts collected from this gateway | | `error` | `string` | no | Failure reason when `ok` is false (e.g. missing credentials) | #### `PostCashJobResult` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `state` | `string` | yes | Outcome as observed by the till. SUCCESS means the machine completed the operation; FAILURE means it refused, faulted or was unreachable. | | `receivedTotal` | `number` | no | Cash the machine took in, in cents. Becomes the recorded tender, so it must come from the machine and never from operator input. | | `dispensedTotal` | `number` | no | Cash the machine paid out, in cents. Becomes the recorded change. | | `code` | `string` | no | Machine-readable failure code, mirroring the provider error tags (device_busy, device_error, unavailable, ...). | | `reason` | `string` | no | Human-readable failure reason for the operator and the logs. | | `deviceStatus` | `object` | no | Raw device status when the machine itself reported a fault. | #### `PrintReceiptDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `transactionId` | `string` | yes | Id of the transaction whose receipt should be printed | | `template` | `string` | no | Receipt template to use | | `receiverId` | `string` | no | Id of the receiver device/printer | | `args` | `object` | no | Extra template arguments passed through to the renderer | #### `ProcessGlovoTransaction` Type: `object` #### `PushPrintDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `transactionId` | `string` | yes | Id of the transaction whose receipt should be printed | | `deviceId` | `string` | no | 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. | | `templates` | `string[]` | no | Templates to print for this transaction | | `args` | `object` | no | Extra template arguments passed through to the renderer | #### `RefundPayload` Type: `object` #### `RefundPayloadV2` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Id of the company issuing the refund | | `paymentId` | `string` | yes | Id of the payment being refunded | | `amount` | `number` | yes | Refund amount in minor units (cents) | | `currency` | `string` | yes | ISO 4217 currency code | | `reason` | `string` | no | Human readable reason for the refund | | `requestedBy` | `string` | no | Identifier of the member/user who requested the refund | | `accountId` | `string` | no | Optional processor account id when operating under a connect/platform account | | `deviceId` | `string` | no | 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. | #### `ReportCashInventoryRequest` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `cashMachineId` | `string` | yes | Cash machine the reading came from | | `totalCents` | `number` | yes | Total held, in cents | | `currency` | `string` | yes | Currency of the amounts | | `denominations` | `CashDenomination[]` | yes | Everything the machine is holding, per denomination | #### `ResolveLoyaltyRequest` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `identifier` | `string` | yes | Customer lookup value: phone number, email, Comeback customer id, or scanned pass/QR code. | | `phoneNumber` | `string` | no | Deprecated: use identifier. Kept for backward compatibility. | | `cart` | `LoyaltyCartLineDto[]` | no | Current cart lines, used to price applicable promotions | #### `SplitSessionBill` Type: `object` #### `Step` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | Optional human readable name of the step | | `action` | `string` | yes | Action executed by this step | | `args` | `object` | no | Action-specific payload | | `settings` | `object` | yes | Step execution settings | #### `SubscriberPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `programId` | `string` | yes | Id of the loyalty/subscription program to join | | `templateId` | `string` | yes | Id of the program template/tier being subscribed to | | `provider` | `string` | yes | Payment provider used to complete the subscription | | `args` | `object` | yes | Provider-specific payload (e.g. Stripe sessionId) | | `returnUrl` | `string` | no | URL the customer is returned to after the provider flow | #### `SubscriptionPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Display name of the subscription product | | `description` | `string` | yes | Marketing description shown to customers | | `image` | `string` | yes | Image URL for the subscription product card | | `items` | `string[]` | yes | Price tiers and their external price ids | | `provider` | `string` | yes | Payment provider managing the subscription | | `locationsIds` | `string[]` | yes | Locations where the subscription is offered | #### `SubscriptionSession` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `subscriptionId` | `string` | yes | Id of the subscription product the customer wants to buy | | `config` | `object` | yes | Redirect URLs the provider should use after checkout | #### `TrackCashRegisterTransaction` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `description` | `string` | no | Optional description or note for the tracked movement | | `trace` | `object` | yes | Trace metadata linking the movement to an order | | `type` | `string` | yes | Cash movement type | | `amount` | `number` | yes | Amount in minor units (cents); positive for inflows, negative for outflows | | `currency` | `string` | yes | ISO 4217 currency code | #### `UpdateCashSnapshot` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `description` | `string` | no | Optional description or note about the snapshot | | `notifyAlert` | `boolean` | no | Whether to raise an alert notification | | `openedAt` | `object` | no | When the register was opened | | `closedAt` | `object` | no | When the register was closed | | `transactions` | `number` | no | Total number of transactions in the shift | | `initialAmount` | `number` | no | Initial cash in drawer (cents) | | `salesAmount` | `number` | no | Sum of sales during the shift (cents) | | `refundsAmount` | `number` | no | Sum of refunds issued during the shift (cents) | | `changeGivenAmount` | `number` | no | Sum of change returned during the shift (cents) | | `changeKeepedAmount` | `number` | no | Sum of change kept (left by customers) during the shift (cents) | | `incomesAmount` | `number` | no | Sum of ad-hoc cash income (cents) | | `outcomesAmount` | `number` | no | Sum of ad-hoc cash outflows (cents) | | `machineDepositsAmount` | `number` | no | Sum of cash swept from the drawer into a linked cash machine during the shift (cents) | | `machineWithdrawalsAmount` | `number` | no | Sum of cash dispensed by a linked cash machine instead of a manual outcome during the shift (cents) | | `expectedAmount` | `number` | no | Expected cash in drawer at close (cents) | | `availableAmount` | `number` | no | Counted cash in drawer at close (cents) | | `diffInitialAmount` | `number` | no | Difference on opening (cents, + over, - under) | | `diffFinalAmount` | `number` | no | Difference on close (cents, + over, - under) | | `openingsSnapshots` | `UpdateSnapshotEntry[]` | no | Opening entries breakdown | | `refundsSnapshots` | `UpdateSnapshotEntry[]` | no | Refund entries breakdown | | `changeKeepedSnapshots` | `UpdateSnapshotEntry[]` | no | Change-kept entries breakdown | | `incomesSnapshots` | `UpdateSnapshotEntry[]` | no | Income entries breakdown | | `outcomesSnapshots` | `UpdateSnapshotEntry[]` | no | Outcome entries breakdown | | `machineDepositsSnapshots` | `UpdateSnapshotEntry[]` | no | Machine-deposit entries breakdown | | `machineWithdrawalsSnapshots` | `UpdateSnapshotEntry[]` | no | Machine-withdrawal entries breakdown | #### `UpdateDiscount` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | no | Scope metadata describing where the discount applies | | `name` | `string` | no | Human readable discount name | | `type` | `string` | no | Whether the discount is a percentage or a fixed amount | | `amount` | `number` | no | Discount value; whole percent for PERCENT (e.g. 10 = 10%) or cents for FIXED (e.g. 1500 = 15.00) | | `codes` | `string[]` | no | List of redemption codes customers can enter to apply the discount | | `singleUse` | `boolean` | no | If true, each code can only be redeemed once per customer | | `appliesToBasePriceOnly` | `boolean` | no | 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). | | `menusIds` | `string[]` | no | Restrict to specific menus by id | | `hidden` | `boolean` | no | If true, the discount is omitted from the browsable POS list but remains redeemable by code/QR. | | `validFrom` | `string` | no | ISO date/time from which the discount becomes valid. Send null to clear. | | `validUntil` | `string` | no | ISO date/time after which the discount expires. Send null to clear. | | `usageLimit` | `object` | no | Usage caps. interval is the calendar reset period (EVER = lifetime). maxGlobal caps total redemptions; maxPerMember caps redemptions per staff member. | | `minOrderAmount` | `number` | no | Minimum pre-discount order total (cents) required to redeem the discount. Send null to clear. | #### `UpdateFee` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the fee to update | | `trace` | `object` | yes | Location scope and provider the fee applies to | | `name` | `string` | yes | Human readable fee name | | `description` | `string` | no | Optional description shown to merchants | | `type` | `string` | yes | Fee computation type: PERCENT (basis points) or FIXED (cents) | | `amount` | `number` | yes | Fee value; basis points for PERCENT (1000 = 10%) or cents for FIXED | | `min` | `number` | no | Optional minimum fee in cents | | `max` | `number` | no | Optional maximum fee cap in cents | #### `UpdateSnapshotEntry` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `createdAt` | `object` | no | When the cash movement happened | | `amount` | `number` | no | Amount of the entry in minor units (cents) | | `description` | `string` | no | Optional description or note | | `currency` | `string` | no | ISO 4217 currency code | #### `UpdateSubscription` Type: `object` #### `UpdateTable` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | | | `zone` | `string` | no | | | `seats` | `number` | no | | | `active` | `boolean` | no | Set to false to archive the table (blocked while occupied) | #### `UpdateTax` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the tax record to update | | `trace` | `object` | yes | Scope metadata (locations and external tax/account ids) | | `name` | `string` | yes | Human readable tax name | | `description` | `string` | no | Optional description shown to merchants | | `type` | `string` | yes | Tax computation type: PERCENT (basis points) or FIXED (cents) | | `amount` | `number` | yes | Tax value; basis points for PERCENT (1000 = 10%) or cents for FIXED | | `min` | `number` | no | Optional minimum tax amount in cents | | `max` | `number` | no | Optional maximum tax cap in cents | | `default` | `boolean` | no | 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. | #### `ValidateMerchantPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `validationURL` | `string` | yes | Apple Pay merchant validation URL returned by the browser | --- ## supply-chain Catalog and inventory: items, meals, menus, modifiers, stock. Base path: `/supply-chain` · scope name: `supply-chain` ### Allergens #### `GET /supply-chain/allergens` **List supported allergens** Returns the catalog of allergens Platomico supports (used to tag consumables, items and meals). Public endpoint. Responses: - `200` — List of allergens ### Analytics #### `GET /supply-chain/analytics/consumptions` **Get consumptions in the range** Returns consumption data grouped by the given bucket size (minutes) or by calendar date. Query parameters: - `range` (required) string Responses: - `200` — Consumption totals grouped by bucket #### `GET /supply-chain/analytics/consumptions/average` **Average consumption for the company** Returns the company's average consumption per bucket across its lifetime. No range parameters. Responses: - `200` — Average consumption metrics #### `GET /supply-chain/analytics/consumptions/count` **Count consumptions in range** Returns the total number of consumption events recorded in the range. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Count of consumption events #### `GET /supply-chain/analytics/consumptions/v2/items` **Items sold in the range (v2)** Returns the number of units sold per item for the given range. Aggregated from transactionsV2. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Counts per item #### `GET /supply-chain/analytics/consumptions/v2/items-and-meals` **Items and meal deals sold in the range (v2)** 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. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Counts per item and per meal deal #### `GET /supply-chain/analytics/consumptions/v2/preparations` **Preparation consumption totals (v2)** Returns total consumption per preparation for the range, with each preparation rolled up to its resolved raw consumables. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Totals per preparation with resolved consumable breakdown #### `GET /supply-chain/analytics/consumptions/v2/preparations-time-series` **Preparation consumption time-series (v2)** Returns a time-series of preparation (sub-recipe) consumption over the given range. Sourced from the consumption records `preparations` array. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Time-series per preparation #### `GET /supply-chain/analytics/consumptions/v2/time-series` **Consumption time-series per ingredient (v2)** Returns a time-series of ingredient consumption over the given range. Used for trend charts. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Time-series per ingredient #### `GET /supply-chain/analytics/consumptions/variance` **Consumption variance in range** Returns the variance between expected (based on sales + recipes) and observed consumption, either as an absolute number or relative percentage. Query parameters: - `type` (required) string Responses: - `200` — Variance breakdown per consumable #### `GET /supply-chain/analytics/dashboard` **Get analytics dashboard data** Returns the aggregated numbers (sales, top items, consumption summary) rendered on the dashboard home for the given time range and optional locations. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Dashboard metrics for the range #### `GET /supply-chain/analytics/items/sales` **Fetch item sales in range** Returns per-item sales totals (count + revenue) for the given range and locations. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Sales totals per item #### `GET /supply-chain/analytics/items/v2/consumption` **Get item-level consumption (v2)** Returns the v2 item-level consumption breakdown (uses transactionsV2 as source). Supports bucket sizes in minutes or by calendar date. Query parameters: - `range` (required) string Responses: - `200` — Item consumption breakdown #### `GET /supply-chain/analytics/purchase-orders/count` **Count purchase orders in range** Returns the number of purchase orders placed in the range, grouped by status. Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — Purchase order counts by status #### `GET /supply-chain/analytics/snapshot/items` **Get all-time record snapshots for items** Returns snapshot records for the given item names and frequency. Used to plot historical sales curves. Query parameters: - `itemsNames` (required) array - `frequency` (required) string Responses: - `200` — Snapshot records per item #### `GET /supply-chain/analytics/stock-timestamps` **Get stock level timestamps** Returns stock snapshots across the requested range and locations (used to render stock-over-time charts). Query parameters: - `locationsIds` string[] — Location ids to scope the query to Responses: - `200` — List of stock snapshots keyed by consumable and timestamp ### Analytics:V2 #### `GET /supply-chain/analytics/v2/consumptions/count` **Count consumptions in range (time-of-day aware)** Query parameters: - `locationsIds` string[] — Location ids to scope the query to - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `type` string — Variance comparison mode (consumptions/variance only) Responses: - `200` #### `GET /supply-chain/analytics/v2/consumptions/v2/items` **Items sold from consumptions v2 (time-of-day aware)** Query parameters: - `locationsIds` string[] — Location ids to scope the query to - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `type` string — Variance comparison mode (consumptions/variance only) Responses: - `200` #### `GET /supply-chain/analytics/v2/consumptions/v2/preparations` **Preparation consumption totals (time-of-day aware)** Query parameters: - `locationsIds` string[] — Location ids to scope the query to - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `type` string — Variance comparison mode (consumptions/variance only) Responses: - `200` #### `GET /supply-chain/analytics/v2/consumptions/v2/preparations-time-series` **Preparation consumption time-series (time-of-day aware)** Query parameters: - `locationsIds` string[] — Location ids to scope the query to - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `type` string — Variance comparison mode (consumptions/variance only) Responses: - `200` #### `GET /supply-chain/analytics/v2/consumptions/v2/time-series` **Consumption time-series per ingredient (time-of-day aware)** Query parameters: - `locationsIds` string[] — Location ids to scope the query to - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `type` string — Variance comparison mode (consumptions/variance only) Responses: - `200` #### `GET /supply-chain/analytics/v2/consumptions/variance` **Consumptions variance (time-of-day aware)** Query parameters: - `locationsIds` string[] — Location ids to scope the query to - `timeWindows` string[] — Intra-day windows to keep, each "startMinute-endMinute" in minutes-of-day, evaluated in `timezone`. Union of windows; absent means all day. - `timezone` string — IANA timezone used to evaluate the time windows - `type` string — Variance comparison mode (consumptions/variance only) Responses: - `200` ### Consumables #### `POST /supply-chain/consumables` **Create a consumable (legacy)** 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. Request body: `Consumable` Responses: - `200` `Consumable` — The created consumable #### `PATCH /supply-chain/consumables` **Update a consumable (legacy)** Updates an existing consumable. Legacy endpoint; prefer PATCH /v2 which normalizes price to cents. Request body: `object` Responses: - `200` — The updated consumable #### `GET /supply-chain/consumables` **List consumables for a location** Returns consumables available at the given location for the current company. Query parameters: - `locationId` (required) string — Identifier of the location to scope the query to Responses: - `200` `Consumable[]` — List of consumables #### `DELETE /supply-chain/consumables` **Delete a consumable** Deletes the consumable with the given id. Fails if it is still referenced by items / preparations / stock. Query parameters: - `id` (required) string — Identifier of the consumable Responses: - `200` — Deletion result #### `POST /supply-chain/consumables/v2` **Create a consumable** Creates a new consumable (raw ingredient, drink base, etc.) for the current company using the v2 pipeline (normalized pricing + image upload). Request body: `Consumable` Responses: - `200` `Consumable` — The created consumable #### `PATCH /supply-chain/consumables/v2` **Update a consumable** Updates an existing consumable using the v2 pipeline (normalized pricing + image upload). Request body: `object` Responses: - `200` — The updated consumable ### Delivery #### `POST /supply-chain/delivery/fees` **Create a delivery fee range** Creates a fee tier (a minimum order threshold + percent fee) for the current company, optionally scoped to specific locations. Request body: `CreateFeeRange` Responses: - `200` — The created fee range #### `GET /supply-chain/delivery/fees` **List delivery fee ranges** Returns the configured delivery fee tiers for the current company, optionally filtered by location. Query parameters: - `locationId` string Responses: - `200` — List of configured fee tiers #### `PATCH /supply-chain/delivery/fees` **Update a delivery fee range** Updates the threshold, type or amount of an existing delivery fee tier. Request body: `UpdateFeeRange` Responses: - `200` — The updated fee range #### `DELETE /supply-chain/delivery/fees` **Delete a delivery fee range** Removes the delivery fee tier with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deletion result ### Health #### `GET /supply-chain/health` **Service health check** Returns the health status of the supply-chain service and its dependencies. Used by uptime probes and orchestrators. Responses: - `200` — Health details per subsystem ### Inventory #### `POST /supply-chain/inventory/retrack/consumptions-v2` **Re-track (regenerate) consumptions in a range** 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. Request body: `object` Responses: - `200` — Summary of the re-track run (or dry-run count) #### `POST /supply-chain/inventory/store` **Create a stock store** Creates a stock store entry (initial inventory) for a consumable at a specific location. Request body: `CreateStockStore` Responses: - `200` — The created stock store #### `PATCH /supply-chain/inventory/store` **Update stock stores at a location** Bulk updates the stock levels for the given consumables at a specific location. Used by the "count inventory" flow. Request body: `UpdateStockStore` Responses: - `200` — Summary of the update #### `DELETE /supply-chain/inventory/store` **Delete a stock store** Removes a stock store entry (by id) for the given location. Query parameters: - `id` (required) string - `locationId` (required) string Responses: - `200` — Deletion result #### `GET /supply-chain/inventory/stores` **List stock stores** Returns the stock stores (current inventory) for the given location ids within the current company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — Stock stores grouped by location #### `POST /supply-chain/inventory/track/consumption-v2` **Track consumption from a transaction (v2)** 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. Request body: `object` Responses: - `200` — Summary of the consumption tracking ### Items #### `POST /supply-chain/items` **Create an item (legacy)** Creates a menu item (dish / drink) for the current company. Legacy pipeline with floating-point rounding issues — prefer POST /v2. Request body: `Item` Responses: - `200` `Item` — The created item #### `GET /supply-chain/items` **List items** Returns items available at the given location ids for the current company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` `Item[]` — List of items #### `PATCH /supply-chain/items` **Update an item (legacy)** Updates an existing item. Legacy pipeline with floating-point rounding issues — prefer PATCH /v2. Request body: `object` Responses: - `200` — The updated item #### `DELETE /supply-chain/items` **Delete an item** Deletes the item with the given id from the current company. Query parameters: - `id` (required) string — Identifier of the item Responses: - `200` — Deletion result #### `GET /supply-chain/items/endpoint` **List items for an endpoint (ordering site)** Returns items available to a public endpoint (ordering web, QR) scoped to the endpoint session and locations. Filters by visibility channel. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` `Item[]` — Items visible on the endpoint #### `GET /supply-chain/items/paged` **List a page of items** 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. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). - `search` string — Free-text search over the record name. Responses: - `200` — A page of items and the total matching the filter #### `POST /supply-chain/items/v2` **Create an item** Creates a menu item (dish / drink) for the current company using the v2 pipeline (normalized pricing). Request body: `Item` Responses: - `200` `Item` — The created item #### `PATCH /supply-chain/items/v2` **Update an item** Updates an existing item using the v2 pipeline (normalized pricing, image upload). Request body: `object` Responses: - `200` — The updated item ### Locales #### `GET /supply-chain/locales` **List locales for a menu** Returns all translation documents attached to the given menu. Used by the admin UI to display translation coverage. Query parameters: - `menuId` (required) string — Menu id to scope the query to Responses: - `200` — List of locale documents #### `POST /supply-chain/locales` **Create a locale** Creates a new translation document for an entity (item, meal, menu, section). Once persisted, downstream services use it to render localized strings. Request body: `CreateLocale` Responses: - `200` — The created locale document #### `PATCH /supply-chain/locales` **Update a locale** Updates the translations or display name of an existing locale document. Request body: `UpdateLocale` Responses: - `200` — The updated locale document #### `GET /supply-chain/locales/base-dictionaries` **Platform base dictionaries for device/web UI strings** 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. Responses: - `200` — Base dictionaries keyed by scope type #### `POST /supply-chain/locales/bulk` **Bulk create/update locales** 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. Request body: `BulkUpsertLocales` Responses: - `200` — Counts of created and updated locale documents #### `GET /supply-chain/locales/by-type` **List locales by type** Returns all locale documents of a given type (ITEM, MEAL, MENU, SECTION, ...) for the current company. Query parameters: - `type` (required) string Responses: - `200` — Locale documents of the given type ### Meals #### `POST /supply-chain/meals` **Create a meal (legacy)** Creates a meal (combo) for the current company. Legacy endpoint that does not normalize price to cents and skips image upload — prefer POST /v2. Request body: `CreateMeal` Responses: - `200` — The created meal #### `PATCH /supply-chain/meals` **Update a meal (legacy)** Updates an existing meal. Legacy endpoint with floating-point pricing issues — prefer PATCH /v2. Request body: `UpdateMeal` Responses: - `200` — The updated meal #### `DELETE /supply-chain/meals` **Delete a meal** Deletes the meal with the given id. Query parameters: - `id` (required) string — Identifier of the meal Responses: - `200` — Deletion result #### `GET /supply-chain/meals` **List meals** Returns meals available at the given location ids for the current company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` — List of meals #### `GET /supply-chain/meals/endpoint` **List meals for an endpoint** Returns meals available to a public endpoint (ordering web, QR) scoped to the endpoint session and locations. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` — Meals visible on the endpoint #### `GET /supply-chain/meals/paged` **List a page of meals** 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. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). - `search` string — Free-text search over the record name. Responses: - `200` — A page of meals and the total matching the filter #### `POST /supply-chain/meals/v2` **Create a meal** Creates a meal (combo: a sequence of steps letting the customer pick items) for the current company. v2 pipeline normalizes price and uploads images. Request body: `CreateMeal` Responses: - `200` — The created meal #### `PATCH /supply-chain/meals/v2` **Update a meal** Updates an existing meal using the v2 pipeline (normalized pricing, image upload). Request body: `UpdateMeal` Responses: - `200` — The updated meal ### Menus #### `GET /supply-chain/menus` **List menus** Returns menus defined at the given location ids for the current company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — List of menus #### `POST /supply-chain/menus` **Create a menu** Creates a new menu (DEFAULT = per-item pricing, DAILY = flat price) with its sections / items for the current company. Request body: `CreateMenu` Responses: - `200` — The created menu #### `PATCH /supply-chain/menus` **Update a menu** Updates an existing menu: sections, items, theme, availability windows, discounts. Request body: `UpdateMenu` Responses: - `200` — The updated menu #### `DELETE /supply-chain/menus` **Delete a menu** Permanently removes the menu with the given id from the current company. Query parameters: - `menuId` (required) string Responses: - `200` — Deletion result #### `POST /supply-chain/menus/{menuId}/discard` **Discard a menu draft** Throws away unpublished edits without touching live content. Pass `channels` to discard a subset; omit it to discard everything pending. Path parameters: - `menuId` (string) Request body: `object` Responses: - `200` — The menu and the channels that were discarded #### `POST /supply-chain/menus/{menuId}/publish` **Publish a menu** 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. Path parameters: - `menuId` (string) Request body: `object` Responses: - `200` — The published menu and the channels that were promoted ### Modifier Groups #### `GET /supply-chain/items/modifiers/groups` **List modifier groups** Returns modifier groups available at the given locations for the current company. Used by the modifier editor combobox. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` `ModifierGroup[]` — List of modifier groups #### `PATCH /supply-chain/items/modifiers/groups` **Update a modifier group** 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. Request body: `UpdateModifierGroup` Responses: - `200` — The updated modifier group - `400` — Unreachable or contradictory bounds, or a member already bound elsewhere ### Modifiers #### `POST /supply-chain/items/modifiers` **Create a modifier (legacy)** Creates an item modifier (topping, extra, size) for the current company. Legacy endpoint that does not convert price to cents — prefer POST /v2. Request body: `Modifier` Responses: - `200` `Modifier` — The created modifier #### `GET /supply-chain/items/modifiers` **List modifiers** Returns modifiers available at the given location ids for the current company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` `Modifier[]` — List of modifiers #### `PATCH /supply-chain/items/modifiers` **Update a modifier (legacy)** Updates an existing modifier. Legacy endpoint that does not convert price to cents — prefer PATCH /v2. Request body: `UpdateModifier` Responses: - `200` — The updated modifier #### `DELETE /supply-chain/items/modifiers` **Delete a modifier** Deletes the modifier with the given id. Query parameters: - `id` (required) string — Identifier of the modifier Responses: - `200` — Deletion result #### `GET /supply-chain/items/modifiers/endpoint` **List modifiers for an endpoint** Returns modifiers available to a public endpoint (ordering web, QR) scoped to the endpoint session and locations. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` — Modifiers visible on the endpoint #### `POST /supply-chain/items/modifiers/v2` **Create a modifier** Creates an item modifier (topping, extra, size) for the current company using the v2 pipeline (normalized pricing). Request body: `Modifier` Responses: - `200` `Modifier` — The created modifier #### `PATCH /supply-chain/items/modifiers/v2` **Update a modifier** Updates an existing modifier using the v2 pipeline (normalized pricing). Request body: `UpdateModifier` Responses: - `200` — The updated modifier ### Orders #### `GET /supply-chain/purchase-orders` **List purchase orders in range** Returns purchase orders placed at the given locations within the date range, optionally filtered by status. Responses: - `200` — List of purchase orders #### `POST /supply-chain/purchase-orders` **Create purchase orders** 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. Request body: `CreateOrder` Responses: - `200` — The created orders #### `PATCH /supply-chain/purchase-orders` **Update a purchase order** Updates a purchase order status (e.g. mark as IN_PROGRESS, RECEIVED, CANCELED) and optionally attaches a delivery note. Request body: `UpdateOrder` Responses: - `200` — The updated order #### `DELETE /supply-chain/purchase-orders` **Delete a purchase order** Deletes the purchase order with the given id from the listed locations. Query parameters: - `id` (required) string — Id of the purchase order to delete - `locationsIds` (required) string[] — Location ids the purchase order belongs to Responses: - `200` — Deletion result #### `GET /supply-chain/purchase-orders/device` **List pending purchase orders for a device** Returns the purchase orders pending reception at the member / device location. Used on-site when receiving a delivery. Responses: - `200` — Pending purchase orders #### `GET /supply-chain/purchase-orders/kanban` **Kanban board of purchase orders** Returns purchase orders grouped by status, suited for a kanban UI. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — Purchase orders grouped by status #### `GET /supply-chain/purchase-orders/one` **Fetch a single purchase order** Returns a purchase order by its id. Query parameters: - `id` (required) string Responses: - `200` — The purchase order #### `GET /supply-chain/purchase-orders/paged` **List a page of purchase orders with the matching total** 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. Responses: - `200` — A page of purchase orders and the total matching the filter #### `GET /supply-chain/purchase-orders/provider` **List purchase orders for a provider** Returns paginated purchase orders filtered by provider within the range and locations. Responses: - `200` — Purchase orders from the provider ### Preparations #### `POST /supply-chain/preparations` **Create a preparation** Creates a preparation (mise en place / sub-recipe that aggregates ingredients into a reusable building block). Consumed by items and other preparations. Request body: `Preparation` Responses: - `200` `Preparation` — The created preparation #### `PATCH /supply-chain/preparations` **Update a preparation** Updates an existing preparation (name, ingredients, serving unit, tags). Request body: `object` Responses: - `200` — The updated preparation #### `GET /supply-chain/preparations` **List preparations at a location** Returns preparations defined at the given location for the current company. Query parameters: - `locationId` (required) string — Identifier of the location to scope the query to Responses: - `200` `Preparation[]` — List of preparations #### `DELETE /supply-chain/preparations` **Delete a preparation** Deletes the preparation with the given id. Fails if still referenced by items or other preparations. Query parameters: - `id` (required) string — Identifier of the preparation Responses: - `200` — Deletion result ### Providers #### `POST /supply-chain/providers` **Create a provider** Creates a supplier / provider record for the current company (used by purchase orders and receptions). Request body: `CreateProvider` Responses: - `200` — The created provider #### `PATCH /supply-chain/providers` **Update a provider** Updates the contact details or reference of an existing provider. Request body: `UpdateProvider` Responses: - `200` — The updated provider #### `GET /supply-chain/providers` **List providers** Returns all providers configured for the current company. Responses: - `200` — List of providers #### `DELETE /supply-chain/providers` **Delete a provider** Deletes the provider with the given id. Does not delete its measures; those must be removed separately. Query parameters: - `id` (required) string Responses: - `200` — Deletion result #### `GET /supply-chain/providers/measure` **List provider measures (packaging) at locations** Returns the packaging units (measures) a provider sells for consumables at the given locations. Used during reception to map a quantity to a price. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — List of measures #### `POST /supply-chain/providers/measure` **Create a provider measure (packaging)** Creates a packaging unit for a consumable sold by a provider at one or more locations. Request body: `CreateMeasure` Responses: - `200` — The created measure #### `PATCH /supply-chain/providers/measure` **Update a provider measure** Updates a provider measure (packaging size, price, linked consumables, reference). Request body: `UpdateMeasure` Responses: - `200` — The updated measure #### `DELETE /supply-chain/providers/measure` **Delete a provider measure** Deletes the provider measure (packaging) with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deletion result ### Receptions #### `PATCH /supply-chain/receptions` **Update a reception** Updates the consumables / packaging details on an existing reception before confirmation. Request body: `UpdateReception` Responses: - `200` — The updated reception #### `DELETE /supply-chain/receptions` **Delete a reception** Deletes the reception with the given id at the given location. Query parameters: - `id` (required) string — Id of the reception to delete - `locationId` (required) string — Location the reception belongs to Responses: - `200` — Deletion result #### `POST /supply-chain/receptions/analyze` **Analyze a delivery note (OCR + extraction)** Runs OCR + extraction on the uploaded delivery note images and returns the parsed line items (provider, consumables, prices). Request body: `AnalyzeDeliveryNote` Responses: - `200` — Extracted delivery note data #### `POST /supply-chain/receptions/analyze-with-agent` **Analyze a delivery note via the AI agent** Analyzes the delivery note using the AI agent pipeline (slower, more accurate). Returns the parsed line items. Request body: `AnalyzeDeliveryNote` Responses: - `200` — Extracted delivery note data #### `PATCH /supply-chain/receptions/confirm` **Confirm a reception** Member confirms a reception once the goods are checked, locking final amounts and prices and updating stock stores. Request body: `ConfirmReception` Responses: - `200` — The confirmed reception #### `POST /supply-chain/receptions/create` **Create a reception (v2)** Persists a reception from the analyzed delivery note: matches consumables, creates/updates measures, and updates stock stores. Request body: `CreateReceptionV2` Responses: - `200` — The created reception #### `PATCH /supply-chain/receptions/device` **Update a reception from a device** Device-side endpoint to update a reception in progress (e.g. during the on-site goods-in flow). Request body: `UpdateReception` Responses: - `200` — The updated reception #### `POST /supply-chain/receptions/device/upload-delivery-note` **Upload delivery note from a device** Uploads delivery note images captured on a device (POS/tablet). Skips duplicate detection when force is true. Request body: `UploadDeliveryNodeFromDevice` Responses: - `200` — Upload result with the created delivery note id #### `GET /supply-chain/receptions/file` **Proxy download a delivery note file** 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. Query parameters: - `url` (required) string Responses: - `200` — Binary file stream of the proxied resource - `400` — Failed to download the requested file #### `PATCH /supply-chain/receptions/fix` **Fix a mismatched reception** Resolves a mismatch between ordered and received quantities by recording the corrected values. Produces audit records for accounting. Request body: `FixReception` Responses: - `200` — The fixed reception #### `GET /supply-chain/receptions/orphans` **List orphan receptions** Returns receptions that exist but are not yet linked to a purchase order (typically deliveries that arrived unexpectedly). Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to Responses: - `200` — Orphan receptions #### `POST /supply-chain/receptions/staff/analyze` **Analyze a delivery note (staff)** Runs the OCR / extraction pipeline on a delivery note, invoked via the staff console. Request body: `AnalyzeDeliveryNote` Responses: - `200` — Extracted delivery note data #### `PATCH /supply-chain/receptions/staff/confirm` **Confirm a reception (staff)** Marks the reception as confirmed from the staff console, recording final amounts and prices. Request body: `StaffConfirmReception` Responses: - `200` — The confirmed reception #### `POST /supply-chain/receptions/staff/create` **Create a reception (staff)** Creates a reception using the v2 pipeline from the staff console (on behalf of the company attached to the session). Request body: `CreateReceptionV2` Responses: - `200` — The created reception #### `POST /supply-chain/receptions/upload-delivery-note` **Upload delivery note for a location** Uploads delivery note images for a specific location. Returns the created delivery note id and file URLs. Request body: `UploadDeliveryNote` Responses: - `200` — Upload result ### Steps #### `POST /supply-chain/steps` **Create a master step** 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. Request body: `CreateStep` Responses: - `200` — The created master step #### `PATCH /supply-chain/steps` **Update a master step** Updates an existing master step. Meals that already copied it are NOT rewritten. Request body: `UpdateStep` Responses: - `200` — The updated master step #### `DELETE /supply-chain/steps` **Delete a master step** Deletes the master step with the given id. Meals keep their copied contents. Query parameters: - `id` (required) string — Identifier of the master step Responses: - `200` — Deletion result #### `GET /supply-chain/steps` **List master steps** Returns master steps available at the given location ids for the current company. Query parameters: - `locationsIds` (required) string[] — Location ids to scope the query to - `includeHidden` boolean — 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). Responses: - `200` — List of master steps #### `PATCH /supply-chain/steps/propagate` **Propagate a master step into meals** 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. Request body: `UpdateStep` Responses: - `200` — How many meals matched and were modified ### Visibility #### `GET /supply-chain/visibility` **Fetch catalog visibility** Returns the per-location, per-channel hidden state of items, meals and modifiers for the current company. Query parameters: - `locationIds` string[] — Optional location ids to scope the read to Responses: - `200` — Visibility map keyed by location id then resource id. Channels whose snooze deadline has already passed are reported as visible. #### `PATCH /supply-chain/visibility` **Toggle catalog visibility on a channel** 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. Request body: `UpdateVisibility` Responses: - `200` — Result of the toggle #### `PATCH /supply-chain/visibility/bulk` **Toggle catalog visibility for a whole group at once** 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. Request body: `UpdateVisibilityBulk` Responses: - `200` — Result of the group toggle #### `POST /supply-chain/visibility/publish` **Republish the platform catalog after availability changes** 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. Request body: `PublishVisibilityMenus` Responses: - `200` — How many locations were queued ### supply-chain schemas #### `Allergen` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name of the allergen | #### `AnalyzeDeliveryNote` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location where the delivery is being analyzed | | `images` | `string[]` | yes | Base64-encoded delivery note images to OCR / analyze | #### `BulkUpsertLocaleItem` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `sourceId` | `string` | yes | Id of the source entity the locale translates (e.g. the menu id) | | `type` | `string` | yes | Type of entity the locale translates (e.g. MENU, ITEM, MEAL) | | `lang` | `string` | yes | Language code of this document (e.g. ES, EN, IT, DE) | | `locales` | `object` | yes | Translations keyed by entity key (item id, ".description", meal id, ...). Merged into any existing document for the same source/type/lang. | | `localeId` | `string` | no | 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. | #### `BulkUpsertLocales` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `items` | `BulkUpsertLocaleItem[]` | yes | The locale documents to create or update | #### `BulkVisibilityResource` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Identifier of the item, meal or modifier | | `type` | `string` | yes | Kind of resource | #### `ConfirmReception` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `receptionId` | `string` | yes | Reception id to confirm | | `providerId` | `string` | yes | Provider that delivered | | `consumables` | `string[]` | yes | Consumables received with their packaging and price | #### `Consumable` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name of the consumable | | `image` | `string` | no | Image URL for the consumable | | `trace` | `any` | yes | Traceability information | | `provider` | `any` | no | Default provider information | | `providers` | `string[]` | no | Alternative provider ids for this consumable | | `unit` | `any` | yes | Unit details of the consumable | | `price` | `any` | no | Pricing details of the consumable | | `knownAs` | `string[]` | no | Other known names of the consumable | | `allergens` | `Allergen[]` | no | Allergens of the consumable | | `tags` | `string[]` | yes | Tags associated with the consumable | #### `ConsumableEntry` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `type` | `string` | no | Type of consumable reference | | `id` | `string` | yes | Identifier of the consumable | | `amount` | `number` | yes | Amount of the consumable used per item | #### `CreateFeeRange` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | no | Trace metadata indicating which locations the fee range applies to | | `min` | `object` | yes | Minimum order amount for this fee tier (in cents) | | `type` | `string` | yes | Type of fee | | `amount` | `number` | yes | Fee amount (percent as integer, e.g. 10 for 10%) | | `currency` | `string` | no | Currency code (ISO 4217) | #### `CreateLocale` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `type` | `string` | yes | Type of entity the locale translates (e.g. ITEM, MEAL, MENU, SECTION) | | `locales` | `object` | yes | Translations keyed by language code | | `trace` | `object` | yes | Trace metadata (default language and source id the locale refers to) | #### `CreateMeal` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name of the meal (combo) | | `description` | `string` | no | Description of the meal | | `image` | `string` | no | Image URL of the meal | | `trace` | `object` | yes | Traceability information for the meal | | `price` | `object` | yes | Base price for the meal (in currency minor unit / cents) | | `steps` | `string[]` | yes | 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. | | `taxes` | `string[]` | no | Tax ids applied to the meal | | `tags` | `string[]` | no | Tags associated with the meal | | `knownAs` | `string[]` | no | Other known names of the meal | | `visible` | `boolean` | no | Record-level visibility. `false` hides the meal from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible. | #### `CreateMeasure` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `image` | `string` | yes | Image URL representing the packaging | | `name` | `string` | yes | Display name for the measure (packaging) | | `amount` | `number` | yes | Amount contained in one packaging unit | | `measure` | `string` | yes | Measurement unit (e.g. grs, ml, unt) | | `price` | `object` | yes | Price per packaging unit (in currency minor unit / cents) | | `trace` | `object` | yes | Traceability info linking the measure to provider, locations and consumable | #### `CreateMenu` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationsIds` | `string[]` | no | Location ids the menu is available at | | `sources` | `string[]` | no | Source ids the menu is bound to (KIOSK, ORDERING, POS, etc.) | | `name` | `string` | yes | Name of the menu | | `type` | `string` | yes | Menu type (DEFAULT = per-item pricing, DAILY = flat price) | | `price` | `object` | no | Flat price when menu is of type DAILY | | `grid` | `string[]` | no | Grid layout cells (positioned items/sections) | | `listType` | `string` | no | List layout variant | | `sections` | `string[]` | yes | Menu sections, each listing items with optional overrides | | `upsells` | `object` | no | Meal-upsell forwarding shared across all layouts, keyed by item id. Omit a key -> legacy detection; "NONE" -> no upsell; -> upsell to it. | | `redirects` | `object` | no | 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; -> selecting the item enters that meal directly with the item preselected as its first step. | | `override` | `object` | no | 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. | | `delivery` | `string[]` | no | Delivery aggregator menu (Glovo / Uber Eats / Just Eat). Single-column section list. Each item carries a platforms array (["*"] = all aggregators). | | `discounts` | `string[]` | yes | Discount ids applied menu-wide | | `tags` | `string[]` | yes | Tags associated with the menu | #### `CreateOrder` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Company the order belongs to | | `locationId` | `string` | yes | Location dispatching the delivery | | `orderId` | `string` | yes | Platomico order id | | `transactionId` | `string` | no | Transaction id associated with the delivery | #### `CreateProvider` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Provider name | | `reference` | `string` | no | Provider's internal reference for accounting | | `email` | `string` | no | Contact email | | `phone` | `string` | no | Contact phone number | #### `CreateReceptionV2` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location where the reception took place | | `fileUrls` | `string[]` | yes | URLs of the uploaded delivery note files | | `deliveryNoteId` | `string` | yes | Delivery note id (from analyze step) | | `provider` | `object` | yes | Provider info. If id is omitted, a new provider is created with the given name. | | `items` | `string[]` | yes | Received items | #### `CreateStep` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name of the master step (the step chip label) | | `title` | `string` | no | Customer-facing title shown on the step context panel (meaningful for MODIFIERS steps) | | `description` | `string` | no | Customer-facing description for the step context panel | | `trace` | `object` | yes | Traceability information for the master step | | `view` | `string` | no | Which content the step offers. ITEMS (default when absent) or MODIFIERS. | | `items` | `string[]` | no | Selectable items for ITEMS steps. Amounts arrive in currency major units and are stored in cents. Always persisted; [] for MODIFIERS steps. | | `modifiers` | `string[]` | no | Selectable modifiers for MODIFIERS steps. price/settings override the modifier catalog values; absent means catalog fallback. | | `limits` | `object` | yes | Pick limits: min required, free included in the combo price, max cap. For MODIFIERS steps min/max bound DISTINCT modifiers. | | `settings` | `object` | yes | Step settings (allowedToSkip = optional step) | | `visible` | `boolean` | no | Record-level visibility. `false` hides the master step from the picker. Absent/`true` = visible. | #### `CreateStockStore` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `consumableId` | `string` | yes | Consumable this stock entry tracks | | `amount` | `number` | yes | Initial stored quantity | | `measure` | `string` | yes | Unit of the stored quantity (e.g. grs, ml, unt) | | `trace` | `object` | yes | Trace metadata indicating which location the stock lives at | | `knownAs` | `string[]` | no | Other known names for the consumable at this location | #### `FetchByType` Type: `object` #### `FixReception` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Trace linking the reception to its delivery note, purchase order and location | | `ordered` | `string[]` | yes | Items that were originally ordered | | `received` | `string[]` | yes | Items actually received (corrected values) | #### `Item` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | no | Company id (required for staff-created items) | | `name` | `string` | yes | Name of the item | | `description` | `string` | no | Description of the item | | `image` | `string` | no | Image URL of the item | | `trace` | `any` | yes | Traceability information | | `price` | `any` | yes | Pricing details of the item | | `consumables` | `ConsumableEntry[]` | yes | List of consumables (ingredients or preparations) composing the item | | `taxes` | `string[]` | no | Tax ids applied to the item | | `modifiers` | `string[]` | no | Modifier ids associated with the item (e.g. toppings, sizes) | | `settings` | `object` | no | Presentation settings (POS-specific) | | `tags` | `string[]` | yes | Tags associated with the item | | `knownAs` | `string[]` | yes | Other known names of the item (used for search / binding) | | `dietary` | `string[]` | no | Dietary categories applicable to the item | | `allergens` | `string[]` | no | Allergen ids associated with the item | | `section` | `string` | no | KDS grouping section (free-text label, e.g. "Bar", "Cocina") | | `visible` | `boolean` | no | Record-level visibility. `false` hides the item from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible. | #### `Modifier` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `any` | no | Modifier id (set by the server on creation) | | `companyId` | `string` | no | Company id (required for staff-created modifiers) | | `name` | `string` | yes | Name of the modifier | | `description` | `string` | yes | Description of the modifier | | `image` | `string` | no | 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. | | `trace` | `object` | yes | Traceability information | | `price` | `object` | yes | Price of the modifier | | `consumables` | `string[]` | yes | Consumables (ingredients) used by this modifier | | `settings` | `object` | yes | Presentation settings for the modifier | | `tags` | `string[]` | yes | Tags associated with the modifier | | `knownAs` | `string[]` | yes | Other known names of the modifier | | `visible` | `boolean` | no | Record-level visibility. `false` hides the modifier from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible. | | `groups` | `string[]` | no | 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. | #### `ModifierGroup` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name of the modifier group | | `description` | `string` | no | Description of the modifier group | | `trace` | `any` | yes | Traceability information | | `modifiersIds` | `string[]` | yes | Identifiers of modifiers that belong to the group | | `limits` | `any` | no | 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. | | `repeatable` | `boolean` | no | 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. | | `settings` | `any` | no | Presentation settings for the group | | `knownAs` | `string[]` | no | Other known names of the group | | `tags` | `string[]` | no | Tags associated with the group | #### `ModifierGroupLimits` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `min` | `number` | yes | Minimum units the customer must select. 0 makes the section optional. | | `max` | `number` | yes | Maximum units the customer may select. Counts units, not distinct options: three of the same option fill a max of 3. | #### `ModifierGroupSettings` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `color` | `string` | no | | | `backgroundColor` | `string` | no | | | `max` | `number` | no | | | `appearInSummary` | `boolean` | no | | #### `ModifierGroupTrace` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationsIds` | `string[]` | no | Identifiers of the locations where the group is available | #### `ObjectId` Type: `object` #### `Preparation` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Name of the preparation | | `description` | `string` | no | Description of the preparation | | `trace` | `any` | yes | Traceability information | | `ingredients` | `PreparationIngredient[]` | yes | List of ingredients (consumables or nested preparations) | | `servingUnit` | `string` | no | Serving unit of the preparation (e.g. grs, ml, unt) | | `tags` | `string[]` | yes | Tags associated with the preparation | | `knownAs` | `string[]` | no | Other known names of the preparation | #### `PreparationIngredient` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `type` | `string` | no | Type of ingredient reference | | `id` | `string` | yes | Identifier of the ingredient (consumable) or nested preparation | | `amount` | `number` | yes | Amount of the ingredient used per batch | | `measure` | `string` | yes | Measure of the ingredient (e.g. grs, ml, unt) | #### `PreparationTrace` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationsIds` | `string[]` | no | Identifiers of the locations where the preparation is produced | #### `Price` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Price amount (in currency minor unit / cents) | | `currency` | `string` | yes | Currency code (ISO 4217) | #### `Provider` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | no | Provider id | | `name` | `string` | no | Provider name | | `reference` | `string` | no | Provider's internal reference for this consumable | #### `PublishVisibilityMenus` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationIds` | `string[]` | yes | Locations whose platform catalog is republished. A till sends its own location; the dashboard can send several. | #### `StaffConfirmReception` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `receptionId` | `string` | yes | Reception id to confirm | | `providerId` | `string` | yes | Provider that delivered | | `locationId` | `string` | yes | Location where the reception took place | | `consumables` | `string[]` | yes | Consumables received with their packaging and price | #### `Trace` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `sku` | `string` | no | Stock Keeping Unit | | `locationsIds` | `string[]` | no | Identifiers of the locations where the item is available | | `bindingsIds` | `string[]` | no | Bindings ids to update after item creation | | `variationId` | `string` | no | 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. | #### `Unit` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `amount` | `number` | yes | Amount of the consumable per unit | | `measure` | `string` | yes | Measure of quantity (e.g. grs, ml, unt) | #### `UpdateFeeRange` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Fee range id to update | | `trace` | `object` | no | Trace metadata indicating which locations the fee range applies to | | `min` | `object` | no | Minimum order amount for this fee tier (in cents) | | `type` | `string` | no | Type of fee | | `amount` | `number` | no | Fee amount (percent as integer, e.g. 10 for 10%) | | `currency` | `string` | no | Currency code (ISO 4217) | #### `UpdateLocale` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `localeId` | `string` | yes | Id of the locale document to update | | `locales` | `object` | yes | Translations keyed by language code | | `name` | `string` | no | Optional display name override for this locale | #### `UpdateMeal` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the meal to update | | `name` | `object` | no | Name of the meal | | `description` | `object` | no | Description of the meal | | `image` | `object` | no | Image URL of the meal | | `trace` | `object` | no | Traceability information | | `price` | `object` | no | Base price for the meal | | `steps` | `object` | no | Steps composing the meal | | `taxes` | `string[]` | no | Tax ids applied to the meal | | `tags` | `string[]` | no | Tags associated with the meal | | `knownAs` | `string[]` | no | Other known names of the meal | | `visible` | `object` | no | Record-level visibility. `false` hides the meal from the management list/pickers while it still resolves wherever it is already referenced. Absent/`true` = visible. | #### `UpdateMeasure` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the measure to update | | `image` | `string` | yes | Image URL representing the packaging | | `name` | `string` | yes | Display name for the measure | | `amount` | `number` | yes | Amount contained in one packaging unit | | `measure` | `string` | yes | Measurement unit (e.g. grs, ml, unt) | | `price` | `object` | yes | Price per packaging unit | | `consumables` | `string[]` | yes | Consumable ids this measure is linked to | | `trace` | `object` | yes | Traceability info | #### `UpdateMenu` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the menu to update | | `name` | `string` | yes | Name of the menu | | `type` | `string` | yes | Menu type | | `price` | `object` | no | Flat price when menu is DAILY | | `grid` | `string[]` | no | Grid layout cells | | `settings` | `object` | yes | Menu presentation settings (theme + availability days) | | `sections` | `string[]` | no | Menu sections with their items | | `upsells` | `object` | no | Meal-upsell forwarding shared across all layouts, keyed by item id. Omit a key -> legacy detection; "NONE" -> no upsell; -> upsell to it. | | `redirects` | `object` | no | 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; -> selecting the item enters that meal directly with the item preselected as its first step. | | `override` | `object` | no | 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. | | `items` | `string[]` | yes | Flat list of items with section assignment | | `delivery` | `string[]` | no | Delivery aggregator menu (Glovo / Uber Eats / Just Eat). Single-column section list. Each item carries a platforms array (["*"] = all aggregators). | | `draftSections` | `object` | no | 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` | `string[]` | no | Unpublished employee/POS grid. Promoted onto `grid`. | | `draftDelivery` | `string[]` | no | Unpublished platforms layout. Promoted onto `delivery`, after which the Sinqro sync pushes it to the aggregators. | | `draftMenuLevel` | `object` | no | Unpublished menu-wide maps (upsells, redirects, override). Promoted onto their live counterparts. Sent whole, like the live keys. | | `discounts` | `string[]` | no | Discount ids applied menu-wide | | `tags` | `string[]` | yes | Tags associated with the menu | | `knownAs` | `string[]` | yes | Other known names for the menu | #### `UpdateModifier` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the modifier to update | | `trace` | `object` | yes | Traceability fields to update | | `image` | `string` | no | 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. | | `price` | `object` | yes | Price of the modifier | | `consumables` | `string[]` | yes | Consumables used by the modifier | | `settings` | `object` | yes | Presentation settings | | `tags` | `string[]` | no | Tags associated with the modifier. Pass `[]` to clear them; omit to keep the stored value. | #### `UpdateModifierGroup` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the modifier group to update | | `name` | `string` | no | | | `description` | `string` | no | | | `modifiersIds` | `string[]` | no | | | `limits` | `any` | no | Selection bounds. Pass `null` to turn the section back into a plain label; omit to keep the stored value. | | `repeatable` | `boolean` | no | | | `settings` | `object` | no | | #### `UpdateOrder` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the purchase order to update | | `locationsIds` | `string[]` | yes | Location ids the purchase order belongs to | | `status` | `string` | yes | New status for the purchase order | | `deliveryNoteId` | `string` | no | Delivery note id attached when the order was received | #### `UpdateProvider` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the provider to update | | `name` | `string` | no | Provider name | | `reference` | `string` | no | Provider's internal reference for accounting | | `email` | `string` | no | Contact email | | `phone` | `string` | no | Contact phone number | #### `UpdateReception` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Trace metadata linking the reception to its purchase order, member and location | | `consumables` | `string[]` | yes | Received consumables with observed amounts and notes | #### `UpdateStep` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Id of the master step to update | | `name` | `object` | no | Name of the master step | | `title` | `object` | no | Customer-facing title for the step context panel | | `description` | `object` | no | Customer-facing description for the step context panel | | `trace` | `object` | no | Traceability information | | `view` | `string` | no | Which content the step offers | | `items` | `object` | no | Selectable items for ITEMS steps | | `modifiers` | `object` | no | Selectable modifiers for MODIFIERS steps | | `limits` | `object` | no | Pick limits | | `settings` | `object` | no | Step settings | | `visible` | `object` | no | Record-level visibility. `false` hides the master step from the picker. | #### `UpdateStockStore` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location being updated | | `stores` | `string[]` | yes | Stock entries being set for the location | #### `UpdateVisibility` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `resourceId` | `string` | yes | Identifier of the item, meal or modifier to toggle | | `resourceType` | `string` | yes | Kind of resource being toggled | | `locationIds` | `string[]` | yes | Location ids the toggle applies to | | `channel` | `string` | yes | Channel the toggle applies to | | `channels` | `string[]` | no | 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. | | `hidden` | `boolean` | yes | true hides the resource on this channel at those locations, false makes it visible again | | `until` | `string` | no | 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. | #### `UpdateVisibilityBulk` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `tags` | `string[]` | no | 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. | | `resources` | `BulkVisibilityResource[]` | no | Explicit resources to toggle, merged with whatever the tags resolve to | | `locationIds` | `string[]` | yes | Location ids the toggle applies to | | `channel` | `string` | yes | Channel the toggle applies to | | `channels` | `string[]` | no | 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. | | `hidden` | `boolean` | yes | true hides every resolved resource on this channel at those locations, false makes them visible again | | `until` | `string` | no | Optional shared deadline for the whole group, as an absolute ISO instant | #### `UploadDeliveryNodeFromDevice` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `force` | `boolean` | yes | If true, bypasses duplicate-detection on the delivery note and creates a new reception anyway. | | `images` | `string[]` | yes | Images of the delivery note captured by the device | #### `UploadDeliveryNote` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Location receiving the delivery | | `images` | `string[]` | yes | Base64-encoded images of the delivery note | --- ## integrations Provider bindings, webhooks, channel events. Base path: `/integrations` · scope name: `integrations` ### Bindings #### `DELETE /integrations/v2/bindings/{id}` **Delete a binding** Permanently removes the binding from the company. Scoped by trace.companyId. Path parameters: - `id` (string) Query parameters: - `companyId` (required) string Responses: - `200` — Deletion result #### `POST /integrations/v2/bindings/bundle` **Create a BUNDLE binding (Square)** Maps (Platomico meal + step item pick) to a single Square ITEM. Used when a Platomico MEAL collapses into a Square ITEM with modifiers. Request body: `CreateBundleBinding` Responses: - `200` — Created BUNDLE binding ### Contracts #### `GET /integrations/v2/contracts` **List contracts** Returns the provider contracts configured for the current company (one contract per provider binding). Responses: - `200` — Company contracts #### `POST /integrations/v2/contracts` **Create a contract** Registers a new contract for the current company against a provider, including credentials (stored encrypted) and the authorization mode. Request body: `CreateContract` Responses: - `200` — Created contract #### `PATCH /integrations/v2/contracts/{id}/active` **Enable or disable a contract** 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. Path parameters: - `id` (string) — Contract id Request body: `SetContractActive` Responses: - `200` — Updated contract #### `PATCH /integrations/v2/contracts/{id}/settings/operations` **Update operations settings** 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. Path parameters: - `id` (string) — Contract id Request body: `UpdateOperationsSettings` Responses: - `200` — Updated contract ### Discounts #### `GET /integrations/discounts` **List discount bindings** Returns discount bindings for the current company, filtered by the optional query. Query parameters: - `defaultId` (required) string[] — The internal id of the record - `defaultType` (required) string — The type of the record - `externalIds` (required) string[] — The external id of the record - `discountIds` (required) string[] — The internal id of the record Responses: - `200` — Matching discount bindings #### `POST /integrations/discounts` **Create a discount binding** Binds a Platomico discount to an external provider discount for the given locations. Request body: `DiscountPayload` Responses: - `200` — Created binding #### `PATCH /integrations/discounts` **Update a discount binding** Partially updates the discount binding with the given id. Query parameters: - `id` (required) string Request body: `DiscountPayload` Responses: - `200` — Updated binding #### `DELETE /integrations/discounts` **Delete a discount binding** Permanently removes the discount binding with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deletion result ### Health #### `GET /integrations/health` **Service health check** Returns liveness/readiness details for integrations-service. Used by load balancers and uptime monitors. Responses: - `200` — Health details for each dependency ### Integrations #### `GET /integrations/` **List generic integration bindings** Returns every integration binding stored for the current company. Responses: - `200` — Integration bindings for the company #### `POST /integrations/` **Create a generic integration binding** Creates a binding between a Platomico entity and an external provider entity. If `both` is true, creates one binding in each direction. Request body: `IntegrationPayload` Responses: - `200` — Created binding(s) ### Integrations:V2 #### `POST /integrations/v2/providers/comeback/locations` **List the Comeback locations for a token** 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. Request body: `object` Responses: - `200` — Comeback locations #### `POST /integrations/v2/providers/deliverect/channels` **List the marketplaces Deliverect can route orders from** 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. Responses: - `201` #### `POST /integrations/v2/providers/deliverect/locations` **List the Deliverect locations reachable with our credentials** 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. Request body: `object` Responses: - `200` — Deliverect locations #### `POST /integrations/v2/providers/deliverect/locations/{locationId}/sync` **Push a location menu to Deliverect on demand** Path parameters: - `locationId` (string) — Platomico location id Responses: - `204` #### `POST /integrations/v2/providers/deliverect/register` **Register a Deliverect location and return the POS webhook URLs** Responses: - `200` #### `GET /integrations/v2/providers/deliverect/sync-products/{locationId}` **Push the location menu to Deliverect** Path parameters: - `locationId` (string) Responses: - `204` #### `POST /integrations/v2/providers/deliverect/sync-products/{locationId}` **Push the location menu to Deliverect** Path parameters: - `locationId` (string) Responses: - `204` #### `POST /integrations/v2/providers/deliverect/webhook/orders/{locationId}` **Receive a Deliverect order for a location** Path parameters: - `locationId` (string) Request body: `ReceiveDeliverectOrderDto` Responses: - `201` #### `POST /integrations/v2/providers/haddock/sync-catalog` Responses: - `201` #### `POST /integrations/v2/providers/sinqro/sync` Responses: - `201` ### Integrations:V2:Events #### `GET /integrations/v2/events/logs` **List event dispatch logs** Returns recent dispatch attempts for the current company, newest first. Query parameters: - `eventType` string - `transactionId` string - `from` string — ISO 8601 lower bound - `to` string — ISO 8601 upper bound - `limit` string — Default 50, max 200 Responses: - `200` — List of EventLog rows #### `POST /integrations/v2/events/subscriptions` **Toggle an event subscription on a contract** 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. Request body: `ToggleEventSubscriptionBody` Responses: - `200` — Updated contract ### Integrations:V2:Loyalty #### `POST /integrations/v2/loyalty/checkout/resolve` Request body: `CheckoutResolveRequestDto` Responses: - `201` #### `POST /integrations/v2/loyalty/orders` Request body: `SyncLoyaltyOrderRequestDto` Responses: - `201` #### `DELETE /integrations/v2/loyalty/orders/{externalOrderId}` Path parameters: - `externalOrderId` (string) Query parameters: - `locationId` (required) string Responses: - `200` ### Integrations:V2:Revolut #### `GET /integrations/v2/providers/revolut/devices` **List the Revolut POS terminals of a location** 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. Query parameters: - `locationId` (required) string — Platomico location id Responses: - `200` — Terminals available at the location ### Integrations:V2:Square #### `GET /integrations/v2/providers/square/catalog/items/{itemId}/image` **Fetch the Square image for a bound catalog entity** 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. Path parameters: - `itemId` (string) — Platomico item or meal id Responses: - `200` — Availability report #### `POST /integrations/v2/providers/square/devices/code` **Create a Square Terminal pairing code** 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. Request body: `CreateSquareDeviceCode` Responses: - `200` — Created Square device code (raw Square shape) #### `GET /integrations/v2/providers/square/devices/code/{id}` **Fetch a Square Terminal pairing code** 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. Path parameters: - `id` (string) — Square device code id Responses: - `200` — Square device code (raw Square shape) #### `POST /integrations/v2/providers/square/parse` **Parse a Square item/meal** Runs the Square strategy parser, translating a single entity between Platomico and Square shapes in the given direction. Scoped by companyId on the payload. Request body: `ParseSquareStrategy` Responses: - `200` — Parsed entity #### `POST /integrations/v2/providers/square/reconcile` **Reconcile Square sales data with Platomico** 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. Request body: `ReconcileSquareDto` Responses: - `200` — Reconciliation report ### Integrations:V2:Webhooks #### `GET /integrations/v2/webhooks` **List webhooks** Returns the custom webhooks of the current company, newest first. The signing secret is never included. Responses: - `200` — Webhooks #### `POST /integrations/v2/webhooks` **Create a webhook** 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. Request body: `CreateWebhook` Responses: - `200` — Created webhook, including its signing secret #### `PATCH /integrations/v2/webhooks/{id}` **Update a webhook** Changes the name, URL, events, locations or active flag. Only the fields present in the body are written. Path parameters: - `id` (string) — Webhook id Request body: `UpdateWebhook` Responses: - `200` — Updated webhook #### `DELETE /integrations/v2/webhooks/{id}` **Delete a webhook** Path parameters: - `id` (string) — Webhook id Responses: - `200` — { id, removed: true } #### `GET /integrations/v2/webhooks/{id}/deliveries` **List recent deliveries** Recent deliveries to this webhook, newest first, each with its latest attempt flattened on top and its retry state. Path parameters: - `id` (string) — Webhook id Query parameters: - `limit` string — Default 20, max 100 Responses: - `200` — Deliveries #### `GET /integrations/v2/webhooks/{id}/secret` **Reveal the signing secret** Returns the secret used to sign deliveries, so a receiver can verify X-Platomico-Signature. Path parameters: - `id` (string) — Webhook id Responses: - `200` — { secret } #### `GET /integrations/v2/webhooks/deliveries` **The delivery log** 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. Query parameters: - `webhookId` string — Only this webhook - `eventType` string - `status` string — PENDING, DELIVERED, EXHAUSTED or CANCELLED - `transactionId` string — Exact transaction id - `from` string — ISO 8601 lower bound - `to` string — ISO 8601 upper bound - `page` string — Default 1 - `pageSize` string — Default 25, max 100 Responses: - `200` — { items, total, page, pageSize } #### `GET /integrations/v2/webhooks/deliveries/{deliveryId}` **One delivery** The delivery with its body as sent and every attempt made so far. Path parameters: - `deliveryId` (string) — Delivery id Responses: - `200` — Delivery detail #### `POST /integrations/v2/webhooks/deliveries/{deliveryId}/cancel` **Stop retrying a delivery** Closes a PENDING delivery as CANCELLED. 409 if it is not pending or an attempt is in flight. Path parameters: - `deliveryId` (string) — Delivery id Responses: - `200` — Delivery detail #### `POST /integrations/v2/webhooks/deliveries/{deliveryId}/redeliver` **Send a delivery again now** 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. Path parameters: - `deliveryId` (string) — Delivery id Responses: - `200` — Delivery detail after the attempt ### Items #### `GET /integrations/items` **List item bindings** Returns item bindings for the current company, filtered by the optional query. Array parameters accept a JSON-encoded string. Query parameters: - `defaultId` (required) string[] — The internal id of the record - `defaultType` (required) string — The type of the record - `externalIds` (required) string[] — The external id of the record - `itemIds` (required) string[] — The internal id of the record Responses: - `200` — Matching item bindings #### `POST /integrations/items` **Create an item binding** Binds a Platomico item to an external provider item for the given locations. Request body: `ItemPayload` Responses: - `200` — Created binding #### `PATCH /integrations/items` **Update an item binding** Partially updates the item binding with the given id. Query parameters: - `id` (required) string Request body: `ItemPayload` Responses: - `200` — Updated binding #### `DELETE /integrations/items` **Delete an item binding** Permanently removes the item binding with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deletion result ### Loyalty settings #### `GET /integrations/v2/loyalty/settings` **Read the loyalty settings of the current company** 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. Responses: - `200` — Loyalty settings #### `PATCH /integrations/v2/loyalty/settings` **Change the loyalty settings of the current company** 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. Request body: `UpdateLoyaltySettings` Responses: - `200` — Updated loyalty settings ### Meals #### `POST /integrations/meals` **Create a meal binding** Binds a Platomico meal to an external provider meal for the given locations. Request body: `MealPayload` Responses: - `200` — Created binding #### `PATCH /integrations/meals` **Update a meal binding** Partially updates the meal binding with the given id. Query parameters: - `id` (required) string Request body: `MealPayload` Responses: - `200` — Updated binding #### `DELETE /integrations/meals` **Delete a meal binding** Permanently removes the meal binding with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deletion result #### `GET /integrations/meals/fetch` **List meal bindings** Returns meal bindings for the current company, filtered by the optional query. Array parameters accept a JSON-encoded string. Query parameters: - `defaultId` (required) string[] — The internal id of the record - `defaultType` (required) string — The type of the record - `externalIds` (required) string[] — The external id of the record - `mealIds` (required) string[] — The meal id of the record Responses: - `200` — Matching meal bindings ### Modifiers #### `GET /integrations/modifiers` **List modifier bindings** Returns modifier bindings for the current company, filtered by the optional query. Array parameters accept a JSON-encoded string. Query parameters: - `defaultId` (required) string[] — The internal id of the record - `defaultType` (required) string — The type of the record - `externalIds` (required) string[] — The external id of the record - `modifierIds` (required) string[] — The id of the modifier Responses: - `200` — Matching modifier bindings #### `POST /integrations/modifiers` **Create a modifier binding** Binds a Platomico modifier to an external provider modifier for the given locations. Request body: `ModifierPayload` Responses: - `200` — Created binding #### `PATCH /integrations/modifiers` **Update a modifier binding** Partially updates the modifier binding with the given id. Query parameters: - `id` (required) string Request body: `ModifierPayload` Responses: - `200` — Updated binding #### `DELETE /integrations/modifiers` **Delete a modifier binding** Permanently removes the modifier binding with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deletion result ### Parser #### `POST /integrations/parser/discounts` **Parse discounts across providers** Translates a discounts payload between Platomico and the provider shape. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `ParserDiscountsPayload` Responses: - `200` — Parsed discounts #### `POST /integrations/parser/items` **Parse items across providers** Given a binding direction and a provider, translates a list of items between Platomico and the external provider shape. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `object[]` Responses: - `200` — Parsed items in the opposite shape #### `POST /integrations/parser/locations` **Parse locations across providers** Translates a locations payload between Platomico and the provider shape. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `ParserlocationPayload` Responses: - `200` — Parsed locations #### `POST /integrations/parser/meals` **Parse meals across providers** Translates a list of meals between Platomico and the provider shape. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `object[]` Responses: - `200` — Parsed meals #### `POST /integrations/parser/modifiers` **Parse modifiers across providers** Translates a list of modifiers between Platomico and the provider shape. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `object[]` Responses: - `200` — Parsed modifiers #### `POST /integrations/parser/orders` **Parse an order across providers** Translates a single order between Platomico and the provider shape. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `object` Responses: - `200` — Parsed order #### `POST /integrations/parser/record` **Parse a single record by id** Fetches a record by id within a company and runs the parser on it. Handy for reprocessing a single failed record. Query parameters: - `binding` (required) string — The binding of the items - `provider` (required) string — The provider of the items Request body: `object` Responses: - `200` — Parsed record ### Providers #### `GET /integrations/v2/providers` **List providers available to the current company** Returns global providers plus providers specifically scoped to this company. Responses: - `200` — Providers visible to the current company ### integrations schemas #### `CheckoutResolveRequestDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | | | `identifier` | `string` | yes | Customer lookup value: phone number, email, Comeback customer id, or scanned pass/QR code. | | `phoneNumber` | `string` | no | | | `cart` | `LoyaltyCartLineDto[]` | no | | #### `CreateBundleBinding` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Owner company id | | `mealIdentifier` | `string` | yes | Platomico meal id (the parent MEAL) | | `stepItemIdentifier` | `string` | yes | Platomico item id of the step pick that, combined with the meal, maps to the Square ITEM | | `squareItemIdentifier` | `string` | yes | Square catalog object id of the target ITEM | | `mealName` | `string` | no | Display name of the meal (used in the bindings table) | | `stepItemName` | `string` | no | Display name of the step item (used in the bindings table) | | `squareItemName` | `string` | no | Display name of the Square ITEM (used in the bindings table) | #### `CreateContract` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `trace` | `object` | yes | Routing metadata: which provider this contract is for, which locations it covers, and the credentials bag | | `settings` | `object` | yes | 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. | #### `CreateProvider` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Human-readable provider name | | `trace` | `object` | yes | Routing metadata: provider slug, parser strategy, and companies it is scoped to (empty = global) | | `settings` | `object` | no | Provider configuration (authorization mode, required env vars / resources, rate limit) | | `active` | `boolean` | no | Whether the provider is available to companies | | `visible` | `boolean` | no | Whether the provider shows up in the integrations UI | #### `CreateSquareDeviceCode` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | Platomico location id the terminal belongs to | | `name` | `string` | no | Display name for the paired terminal | #### `CreateSquareOrder` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | Owner company id | | `locationId` | `string` | yes | Square location id | | `source` | `string` | yes | Order source (channel) | | `name` | `string` | yes | Order name / customer reference | | `type` | `string` | yes | Order type (e.g. DINE_IN, TAKEAWAY, DELIVERY) | | `note` | `string` | no | 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. | | `pickup` | `string` | no | Pickup time (ISO 8601). When present the fulfillment is SCHEDULED. | | `pickupType` | `string` | no | Source pickup type hint (e.g. 'SCHEDULED', 'ASAP'). Informational; the fulfillment schedule is driven by whether `pickup` is set. | | `metadata` | `object` | no | Arbitrary metadata forwarded to Square | | `discounts` | `string[]` | no | Order-level discounts | | `order` | `string[]` | yes | Order line items (with optional modifiers) | #### `CreateWebhook` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Label shown in the dashboard | | `url` | `string` | yes | HTTPS endpoint that receives the POST | | `events` | `string[]` | yes | Event types to deliver. Any of transaction.created, transaction.refunded, order.updated. | | `locationsIds` | `string[]` | no | Locations whose events are delivered. Empty or omitted means every location. | #### `DiscountPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `discountId` | `string` | yes | The id of the discount | | `externaldiscountId` | `string` | yes | The external id of the discount | | `externalType` | `string` | yes | The external type of the discount | | `binding` | `string` | yes | The binding of the discount | | `locations` | `string[]` | yes | The locations of the discount | #### `IntegrationPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `defaultId` | `string` | yes | The id of the record | | `mealId` | `string` | yes | The meal id of the record | | `externalId` | `string` | yes | The external id of the record | | `defaultType` | `string` | yes | The default type of the record | | `externalType` | `string` | yes | The external type of the record | | `binding` | `string` | yes | The binding of the Integration | | `locations` | `string[]` | yes | The locations of the record | #### `ItemPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `itemId` | `string` | yes | The id of the item | | `externalItemId` | `string` | yes | The external id of the item | | `externalType` | `string` | yes | The external type of the item | | `binding` | `string` | yes | The binding of the item | | `locations` | `string[]` | yes | The locations of the item | #### `LoyaltyCartLineDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `reference` | `string` | yes | | | `name` | `string` | yes | | | `quantity` | `number` | yes | | | `unitAmount` | `number` | yes | | #### `LoyaltyOrderProductDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `reference` | `string` | yes | | | `name` | `string` | yes | | | `quantity` | `number` | yes | | | `unitAmount` | `number` | yes | | #### `MealPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `mealId` | `string` | yes | The id of the meal | | `externalMealId` | `string` | yes | The external id of the meal | | `externalType` | `string` | yes | The external type of the meal | | `binding` | `string` | yes | The binding of the meal | | `locations` | `string[]` | yes | The locations of the meal | #### `ModifierPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `modifierId` | `string` | yes | The id of the Modifier | | `externalModifierId` | `string` | yes | The external id of the Modifier | | `externalType` | `string` | yes | The external type of the Modifier | | `binding` | `string` | yes | The binding of the Modifier | | `locations` | `string[]` | yes | The locations of the Modifier | #### `ParseDefaultStrategy` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Platomico id (or external id, depending on direction) of the entity to resolve | | `type` | `string` | yes | Entity kind | | `modifiers` | `string[]` | no | Attached modifiers and their quantities | | `quantity` | `number` | no | Quantity of this item in the order | | `steps` | `string[]` | no | Nested meal steps (2D array: steps → picks per step) | | `companyId` | `string` | yes | Owner company id | | `direction` | `string` | yes | Direction of the parse. LTR = Platomico→provider, RTL = provider→Platomico. | #### `ParserDiscountsPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `discounts` | `string[]` | yes | Array of discountss | #### `ParseRevolutStrategy` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Platomico id (or external id, depending on direction) of the entity to resolve | | `type` | `string` | yes | Entity kind | | `modifiers` | `string[]` | no | Attached modifiers and their quantities | | `quantity` | `number` | no | Quantity of this item in the order | | `steps` | `string[]` | no | Nested meal steps (2D array: steps → picks per step) | | `companyId` | `string` | yes | Owner company id | | `direction` | `string` | yes | Direction of the parse. LTR = Platomico→Revolut, RTL = Revolut→Platomico. | #### `ParserlocationPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locations` | `string[]` | yes | Array of locations | #### `ParseSquareStrategy` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Platomico id (or external id, depending on direction) of the entity to resolve | | `type` | `string` | yes | Entity kind | | `modifiers` | `string[]` | no | Attached modifiers and their quantities | | `quantity` | `number` | no | Quantity of this item in the order | | `steps` | `string[]` | no | Nested meal steps (2D array: steps → picks per step) | | `companyId` | `string` | yes | Owner company id | | `direction` | `string` | yes | Direction of the parse. LTR = Platomico→Square, RTL = Square→Platomico. | #### `ReceiveDeliverectOrderDto` Type: `object` #### `ReconcileSquareDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | no | Ignored — the company is always resolved from the session token. | | `date` | `string` | no | Single-day shortcut (ISO date). Use from/to for ranges. | | `from` | `string` | no | Inclusive range start (ISO date) | | `to` | `string` | no | Inclusive range end (ISO date) | | `provider` | `string` | no | Optional provider filter (defaults to Square) | | `mode` | `string` | no | scan = report discrepancies only; fix = apply corrections | #### `SetContractActive` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `active` | `boolean` | yes | 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. | #### `SyncLoyaltyOrderRequestDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `locationId` | `string` | yes | | | `customerId` | `string` | yes | | | `externalId` | `string` | yes | | | `totalAmount` | `number` | yes | | | `discountAmount` | `number` | yes | | | `products` | `LoyaltyOrderProductDto[]` | yes | | | `appliedPromotionIds` | `string[]` | yes | | #### `ToggleEventSubscriptionBody` Type: `object` #### `UpdateLoyaltyReward` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | What the till prints on the ticket when the reward is taken | | `points` | `number` | yes | What the reward costs the customer, in points | | `eligibleItemIdentifiers` | `string[]` | yes | 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. | | `eligibleQuantity` | `number` | yes | How many of an eligible meal the reward covers | #### `UpdateLoyaltySettings` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `pointsPerUnit` | `number` | no | Points earned per whole currency unit charged, floored. 100 means a 8,00 € sale earns 800 points. | | `reward` | `any` | no | The reward on offer. Sent whole — a partial reward is not a reward. | #### `UpdateOperationsSettings` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `print` | `object` | no | Toggle physical receipt printing for orders coming from this contract | | `aiResolution` | `object` | no | 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. | | `deliveryParty` | `string` | no | 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. | #### `UpdateWebhook` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | no | | | `url` | `string` | no | | | `events` | `string[]` | no | | | `locationsIds` | `string[]` | no | Empty means every location. | | `active` | `boolean` | no | Pause (false) or resume (true) deliveries. | --- ## common Files, notifications, print jobs, audit trail. Base path: `/common` · scope name: `common` ### AI #### `POST /common/ai` **Send a message to an AI model** 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). Request body: `OnMessage` Responses: - `200` — Assistant reply with the updated chat context ### AI:Brain #### `POST /common/ai/brain` **Create a brain** Creates a brain (persona + role + backing model) attached to the signed-in user’s current company. Request body: `CreateBrain` Responses: - `200` — Created brain ### AI:Context #### `POST /common/ai/context` **Create an AI context** Creates a reusable knowledge block (cases + solutions) that can be attached to an AI model via its trace.modelId. Request body: `CreateContext` Responses: - `200` — Created context ### AI:Models #### `POST /common/ai/model` **Create an AI model** Creates an AI model container. Brains, tools and contexts are attached separately via their own endpoints. Request body: `CreateModel` Responses: - `200` — Created model ### AI:Tools #### `POST /common/ai/tools` **Create a tool** Registers a tool the AI can call. The tool is backed by an internal RPC and typed input/output schemas. Request body: `CreateTool` Responses: - `200` — Created tool ### Audit #### `GET /common/audit` **Search the audit trail for the caller company** Requires the audit-log permission. Company scope always comes from the session; a companyIdentifier in the query is ignored. Query parameters: - `companyId` string — Company scope. Forced to the caller company on the HTTP route; only the internal RPC may set it freely - `locationId` string — Filter by location - `actorId` string — Filter by the user who acted - `actorType` string - `action` string — Exact action, or a prefix such as `users.` to match a whole domain - `entityType` string - `entityIdentifier` string — Filter by the affected record - `result` string - `channel` string - `startDate` string - `endDate` string - `skip` number - `take` number — Capped at 200 Responses: - `200` — Matching audit records, newest first #### `GET /common/audit/catalogue` **The catalogue of audited actions** Responses: - `200` — Action key, entity and retention class #### `POST /common/audit/dashboard` **Record a dashboard action for the calling user** 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. Request body: `RecordDashboardAction` Responses: - `200` — Recorded ### Claude #### `POST /common/claude/translate` **Translate catalog strings** 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. Request body: `TranslateLocalesPayload` Responses: - `200` — The translated entries, keyed by the same ids. ### Files #### `GET /common/files/trim` **Shorten a file URL** 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. Query parameters: - `url` (required) string — Full file URL to trim Responses: - `200` — Shortened URL ### Forms #### `POST /common/forms` **Create a form** Creates a form definition for the signed-in user’s company. Submissions are routed to the listed receivers. Request body: `CreateForm` Responses: - `200` — Created form #### `POST /common/forms/submit` **Submit a form** Submits values for a previously-created form. Triggers notifications to the form’s receivers. Request body: `SubmitForm` Responses: - `200` — Submission receipt ### Health #### `GET /common/health` **Service health check** Returns liveness/readiness details for common-service. Used by load balancers and uptime monitors. Responses: - `200` — Health details for each dependency ### Mails #### `GET /common/mail/update-notification-status/{id}` **Email open-tracking pixel** Serves a 1x1 PNG tracking pixel and marks the referenced notification as opened. Embedded in outgoing HTML emails. Path parameters: - `id` (string) — Notification id encoded in the tracking URL Responses: - `200` — 1x1 transparent PNG ### Menu Import #### `POST /common/menu-import` **Start a menu import (async)** 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. Request body: `MenuImportPayload` Responses: - `200` — The started job. #### `GET /common/menu-import/{jobId}` **Poll a menu-import job** 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. Path parameters: - `jobId` (string) Responses: - `200` — The current job state. #### `POST /common/menu-import/{jobId}/continue` **Resume a bot-flagged import** 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. Path parameters: - `jobId` (string) Responses: - `200` ### Notifications #### `POST /common/notifications/subscribe` **Subscribe a user to a notification channel** Opts a user in to a given (channel, userType) pair. If `isRequired` is true, the user cannot later unsubscribe. Request body: `NotificationsPayload` Responses: - `200` — Subscription created #### `POST /common/notifications/unsubscribe` **Unsubscribe a user from a notification channel** Opts a user out of a given (channel, userType) pair. Request body: `NotificationsPayload` Responses: - `200` — Subscription removed ### Notifications:Templates #### `GET /common/notifications/templates` **Search notification templates** Returns templates for the signed-in user’s current company, filtered by any subset of NotificationTemplatePayload. Responses: - `200` — Matching templates #### `POST /common/notifications/templates` **Create a notification template** Creates a reusable template for the signed-in user’s current company. Request body: `NotificationTemplatePayload` Responses: - `200` — Created template #### `PATCH /common/notifications/templates` **Update a notification template** Partially updates the template with the given id. Query parameters: - `id` (required) string Request body: `NotificationsPayload` Responses: - `200` — Updated template #### `DELETE /common/notifications/templates` **Delete a notification template** Permanently removes the template with the given id. Query parameters: - `id` (required) string Responses: - `200` — Deleted ### PrintJobs #### `POST /common/print-jobs/ack` **Acknowledge printed jobs** Marks the given job ids as PRINTED so they stop being returned by /pending. Request body: `object` Responses: - `200` #### `GET /common/print-jobs/pending` **List pending print jobs for the current device** 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. Responses: - `200` — Pending jobs #### `POST /common/print-jobs/preview` **Preview a print template as an image** Compiles a print template with the given args and returns the rendered PNG inline. Used for thermal printer previews. Request body: `object` Responses: - `200` — Rendered ticket image ### common schemas #### `AuditActor` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `userId` | `string` | yes | The user who acted | | `name` | `string` | yes | | | `email` | `string` | yes | | | `role` | `string` | yes | | #### `AuditChangeEntry` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `field` | `string` | yes | | | `from` | `object` | yes | | | `to` | `object` | yes | | #### `AuditEntityReference` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `identifier` | `string` | yes | | | `label` | `string` | yes | Human-readable name of the affected record, denormalised | #### `AuditOrigin` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `service` | `string` | yes | | | `module` | `string` | yes | | | `channel` | `string` | yes | | | `method` | `string` | yes | | | `path` | `string` | yes | | | `ipAddress` | `string` | yes | | | `userAgent` | `string` | yes | | | `requestIdentifier` | `string` | yes | Correlates every record produced by one HTTP request | #### `AuditScope` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | yes | | | `companyName` | `string` | yes | | | `locationIds` | `string[]` | no | Every location in scope. `['*']` means all of them; an explicit list means those and no others. | #### `CreateAuditRecord` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `action` | `string` | yes | Catalogued action. Rejected if absent from AUDIT_CATALOG | | `actorType` | `string` | yes | | | `result` | `string` | yes | | | `actor` | `AuditActor` | yes | | | `scope` | `AuditScope` | yes | | | `entity` | `AuditEntityReference` | yes | | | `origin` | `AuditOrigin` | yes | | | `message` | `string` | no | Rejection reason on FAILURE or DENIED, empty otherwise | | `changes` | `AuditChangeEntry[]` | no | Before/after pairs. Empty when the action is not a change | | `metadata` | `object` | no | | #### `CreateBrain` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Human-readable brain name | | `description` | `string` | yes | What the brain is for | | `role` | `string` | yes | System prompt / persona the brain adopts | | `trace` | `object` | yes | Routing metadata: which AI model backs this brain | #### `CreateContext` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Human-readable context name | | `description` | `string` | no | Optional short description | | `content` | `object` | yes | Structured knowledge attached to the context | | `trace` | `object` | yes | Routing metadata: which AI model this context belongs to | #### `CreateFile` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `base64` | `string` | yes | Base64-encoded file content (no data: prefix) | | `companyId` | `string` | yes | Owner company id | | `locationId` | `string` | no | Optional owner location id | | `ext` | `string` | no | File extension (without dot) | | `acl` | `string` | no | S3 ACL. Use "public-read" for publicly served assets, empty for private. | | `path` | `string` | no | Destination path/prefix within the bucket | | `contentType` | `string` | no | MIME type | | `removeBackground` | `boolean` | no | When true, the image's background is removed via Pixelcut before storing (images only). The stored asset becomes a transparent PNG. | #### `CreateForm` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Form name | | `receivers` | `string[]` | yes | User ids that will receive submissions | | `locationId` | `string` | no | Scope the form to a location | #### `CreateModel` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Human-readable model name | | `description` | `string` | no | Optional short description | #### `CreateQrDto` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `url` | `string` | yes | Destination URL the QR encodes | | `trace` | `object` | yes | Routing metadata: owner company | #### `CreateTool` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Tool name exposed to the AI | | `description` | `string` | no | What the tool does (the model reads this) | | `settings` | `object` | yes | Backing configuration: which internal model owns it, which RPC to call, and input/output schemas | | `trace` | `object` | yes | Routing metadata: which AI model this tool is attached to | #### `ExportInvoicesByEmailPayload` Type: `object` #### `FetchAuditRecords` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `companyId` | `string` | no | Company scope. Forced to the caller company on the HTTP route; only the internal RPC may set it freely | | `locationId` | `string` | no | Filter by location | | `actorId` | `string` | no | Filter by the user who acted | | `actorType` | `string` | no | | | `action` | `string` | no | Exact action, or a prefix such as `users.` to match a whole domain | | `entityType` | `string` | no | | | `entityIdentifier` | `string` | no | Filter by the affected record | | `result` | `string` | no | | | `channel` | `string` | no | | | `startDate` | `string` | no | | | `endDate` | `string` | no | | | `skip` | `number` | no | | | `take` | `number` | no | Capped at 200 | #### `FetchPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | no | Specific log entry id | | `level` | `string` | no | Filter by log level | | `service` | `string` | no | Filter by originating service | | `environment` | `string` | no | Filter by environment | | `userId` | `string` | no | Filter by user id | | `requestId` | `string` | no | Filter by request correlation id | | `companyId` | `string` | no | Filter by company id | | `locationsIds` | `string[]` | no | Filter by location ids | | `startDate` | `string` | no | Inclusive start of the time window | | `endDate` | `string` | no | Exclusive end of the time window | #### `InternalNotification` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `email` | `string` | yes | Recipient email | | `template` | `string` | yes | Template id/name to render | | `mailArgs` | `object` | no | Arguments injected into the email template | | `attachments` | `string[]` | no | Attachments to include in the email | #### `Logs` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `level` | `string` | yes | Log severity | | `service` | `string` | yes | Originating service | | `module` | `string` | no | Originating module within the service | | `message` | `string` | yes | Human-readable message | | `environment` | `string` | yes | Environment name | | `metadata` | `object` | no | Free-form structured metadata to attach to the log entry | | `trace` | `object` | yes | Correlation trace linking the log to a request, user and scope | #### `Menu` Type: `object` #### `MenuImportPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `input` | `string` | yes | Free text identifying the restaurant: name plus location info (address / city / Google Maps / URL). | | `companyId` | `string` | no | Company the catalog is created for. Defaults to the authenticated session company when omitted. | | `force` | `boolean` | no | Re-import even if the company already has a catalog. Defaults to false (a company that already has items is skipped to avoid duplicates). | #### `NotificationsPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `channel` | `string` | yes | Delivery channel | | `userType` | `string` | yes | Recipient user type | | `isRequired` | `boolean` | yes | If true, the user cannot opt out of this notification | | `userId` | `string` | yes | Recipient user id | #### `NotificationTemplatePayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `name` | `string` | yes | Template name | | `description` | `string` | yes | Short description shown in the template picker | | `type` | `string` | yes | Channel this template is rendered for | | `subject` | `string` | yes | Email subject (or SMS first line) | | `previewText` | `string` | yes | Preview text shown in the inbox | | `url` | `string` | yes | URL of the template source (MJML/HTML/text) | | `lang` | `string` | yes | Language code | | `locationsIds` | `string[]` | yes | Locations this template is enabled for | #### `OnMessage` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `content` | `string` | yes | User message content to send to the AI | | `trace` | `object` | yes | Routing metadata: which model handles the request and which chat to append to | #### `RecordDashboardAction` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `action` | `string` | yes | One of the actions the BFF may record: the dashboard.* entries, plus the sign-in and sign-out it witnesses | | `result` | `string` | yes | | | `resource` | `string` | yes | The route or resource acted on | | `method` | `string` | no | | | `message` | `string` | no | | | `locationIds` | `string[]` | no | 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. | | `metadata` | `object` | no | | #### `SearchRecords` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `directory` | `string` | yes | Directory / path prefix to search under | | `companyId` | `string` | yes | Owner company id | | `ext` | `string` | yes | Restrict to files with this extension | #### `SendInvoiceEmailPayload` Type: `object` #### `SmsMessagePayload` Type: `object` #### `SmsPayload` Type: `object` #### `SubmitForm` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `form` | `string` | yes | Form id to submit to | | `inputs` | `string[]` | yes | Answered fields. TEXT values contain the typed string; FILE values contain the uploaded file URL. | #### `TranslateLocaleEntry` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `id` | `string` | yes | Stable identifier for this string (preserved in the result) | | `text` | `string` | yes | The source-language text to translate | #### `TranslateLocalesPayload` | Field | Type | Required | Notes | | --- | --- | --- | --- | | `sourceLang` | `string` | yes | Source language code (e.g. ES, EN) | | `targetLang` | `string` | yes | Target language code (e.g. IT, DE, JP, CH, AR) | | `entries` | `TranslateLocaleEntry[]` | yes | The strings to translate, each with a stable id | #### `UrlList` Type: `object`