{
  "openapi": "3.0.4",
  "info": {
    "title": "Kombine Flex Portal API",
    "description": "Build your own portal or agent using **HTTPS and JSON**.\r\n\r\n### Get started\r\n\r\n1. Call `LoginManager` with your manager credentials.\r\n2. Copy `accessToken` into **Authorize → ManagerBearer**. Paste only the token; Swagger adds the `Bearer` prefix.\r\n3. Call `GetCurrentManager` to read your profile, tabs, scopes and operation rights.\r\n\r\nNo API key, OAuth client registration or special agent protocol is required.\r\n\r\n**MCP (unreleased):** `POST /mcp` exposes approved JSON read and write operations through stateless Streamable HTTP. Configure the same manager bearer token on every request; each tool retains the API's tenant, Tab, KID and operation checks. See [MCP setup and examples](../docs#mcp). Login and token renewal remain ordinary HTTPS operations; OAuth discovery and browser consent are not provided.\r\n\r\n**Internal assistant (MCP migration, unreleased):** `AskPortalAssistant` discovers and calls its eight approved read tools through the same MCP endpoint. Its host exposes their MCP names and JSON schemas to the model, keeps the manager token in server-side HTTP headers, and retains existing skills and read limits. The broader MCP write catalogue is not available to the internal assistant. Swagger remains available for API exploration and contract tooling.\r\n\r\n### Tenant and language\r\n\r\n- **Host:** `api.{tenant}.kombine.technology` or `beta.api.{tenant}.kombine.technology`. Tokens are bound to the tenant hostname and deployment environment. Unknown hosts return HTTP 400.\r\n- **Language:** send `Accept-Language`, for example `da-DK` or `en-GB`, to localize unit-name placeholders. `Content-Language` identifies the selected language; English is the default.\r\n- **Anonymous access:** select **Public v1 (no login)** above for status, statistics, the purchase map and icon images rendered from local assets.\r\n- **File downloads:** select **Downloads v1** above for resident CSV, account CSV/Excel, settlement ZIP and document CSV/XLS exports. Reuse your manager bearer token.\r\n\r\n### Available operations\r\n\r\nServices1 adds `GetServices`, `GetService` and `SetServiceProfileField` for predefined services. Only names and icons can be edited directly; API-key hashes are read-only. `GenerateServiceApiKey` creates a key starting with `kt_` and stores its password-compatible hash in eSetting.ApiKeyHash. Managers can generate their own key in My settings and use kid/apiKey with LoginManager or Equipment LoginService. Requires Service Read and tenant-wide access; editing/generation also requires Service Write. Key generation does not issue bearer tokens.\r\n\r\n| Area | Operations and access |\r\n| --- | --- |\r\n| Hosting | `GetHostingMetrics` reads DigitalOcean app and Managed MySQL metrics. Requires Hosting1, Managers Read and a whole-tenant KID grant. Metrics cover the shared infrastructure across customers. See [hosting metrics](../docs#hosting). |\r\n| Tenant status | `GetTenantStatus` runs Offline and AutoOutOfOrder lookups in parallel. Requires TenantStatus1, Bank/Location/Unit Read and matching KID scope. Check each source for failure or truncation. See [operational alerts](../docs#tenant-status). |\r\n| Profile | `GetCurrentManager` returns your current access. `GetMyManagerProfile` / `SetMyManagerProfileField` read/edit your own name, organisation, person icon, theme and RetentionDays (deleted-record visibility within existing access). `RequestMyManagerEmailVerification` / `ConfirmMyManagerEmail` verify a new mailbox; `ChangeMyManagerPassword` requires the current password and matching new entries. `SetCurrentManagerTheme` also saves your preference: System = 0, Light = 1, Dark = 2. See [personal settings](../docs#my-settings). |\r\n| Installers | `GetInstallers` lists installer IDs, names, email, locations, tags, state and activity with filtering and paging. `GetInstaller` reads details and the Person icon catalogue. Both reads require Installers1, Installer Read and tenant-wide access; `SetInstallerIcon` additionally requires Installer Write and the current icon revision. |\r\n| Administrators | `GetManagers` lists administrators; `GetManager` reads one canonical manager KID. Both require Managers1, Managers Read and tenant-wide access. `SetManagerPermission` edits one bit; `SetManagerPermissionRole` applies a complete predefined matrix atomically. Both writes additionally require Managers Write; own permissions are editable only for the sole active tenant-wide manager. |\r\n| Residents | `GetBankUsers`, `GetBankUserWorkspace` and `ExportBankUsers` provide authorized Users2 lists, workspace details and bounded CSV export. `CreateBankUser` and `ExecuteBankUserCommand` require bank-wide scope, revision checks and the operation-specific User flags. `GetBankUserActivation` requires User Create. |\r\n| Resident receipts | `GetUserReceipts` returns complete receipts with currency-separated totals and balances, twenty at a time. Requires Users2, User Read and bank-wide scope. Continue with the returned revision and nextOffset. See [receipts](../docs#user-receipts). |\r\n| Locations and units | `GetBankLocations` and `GetLocationUnits` provide authorized overviews, including unit types. `GetUnitIcons` lazily adds online/offline status; `GetLocationIcons` aggregates authorized units into a location status icon; `GetBankIcons` does the same across the bank's authorized locations. `GetUnitOverview` returns the unit's setting/state groups; `GetUnitGroup` reads values, sync flags, editors and edit constraints. `GetUnitSettingHistory` pages through a setting's changes on demand. `SetUnitSetting` saves with Unit Write and revision protection. States remain read-only. |\r\n| Settlements | `GetBankSettlements`, `GetBankSettlementPeriod` and `DownloadBankSettlement` provide read-only history, provisional totals and ZIP downloads. |\r\n| Opening hours | `GetLocationOpeningHours` returns grouped weekly schedules, dated exceptions, nullable opening status and the next change in the location time zone. Same scope and read permissions as the location/unit overview. See [opening hours](../docs#location-opening-hours). |\r\n| Reservation rules | `GetLocationBookingRules` returns configured rules for visible units, grouped by calendar and complete policy. Localized plain text, stable codes and explicit warnings; not a resident-specific availability check. Same scope and read permissions as the location/unit overview. See [reservation rules](../docs#location-booking-rules). |\r\n| Reservation calendars | `GetLocationBookingCalendars` returns version-3 weekly schedules, grouping visible units by their stored calendar identity. Requires Bookings1, Location/Unit Read and matching scope. Configuration only; no occupancy or booking rights. See [reservation calendars](../docs#location-booking-calendars). |\r\n| Reservations | `GetBankBookings` and `ExecuteBankBookingCommand` support Bookings1 lists, cancellation and restoration. Commands require Unit Write; event KIDs supply concurrency checks. |\r\n| Consumption | `GetBankAccount` and `ExportBankAccount` honor location grants. `ReverseBankAccountEntry` requires bank-wide scope and Bank/User Write. |\r\n\r\n`GetCurrentManager.databaseAccess` is a cached indicator for the workspace footer. It does not grant manager permissions or guarantee writes to every bank. See each operation for its complete access requirements.\r\n\r\n**Integration guides:** [English](../docs) · [Dansk](../docs/da) · [Español](../docs/es)",
    "version": "v1"
  },
  "paths": {
    "/api/v1/banks/{bankKid}/account/icon": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "summary": "Resolve the Forbrug icon text from the most frequent authorized Log1 currency.",
        "description": "Requires the same active manager, Account2 and Bank/Location/Unit/User Read permissions as GetBankAccount.\r\n            Counts rows across all periods and entry types, restricted to authorized locations. This is frequency, not amount.\r\n            Trimmed three-letter currencies are uppercased; blanks/malformed codes are ignored. Alphabetical code breaks ties.\r\n            Empty data returns currency=null and the base tab icon without text. No-store; no ledger details are returned.\r\n            400 invalid bank, 401 expired session, 403 denied, 503 storage unavailable.",
        "operationId": "GetBankAccountIcon",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AccountIconResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountIconResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountIconResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/account": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "summary": "Lists Account2 postings with full-selection totals per currency.",
        "description": "### Access\r\n            \r\n- Requires **Account2** and **Bank, Location, Unit and User Read**.\r\n- Location grants limit the rows, totals and available filter choices.\r\n- No business data is read when access is denied.\r\n            \r\n### Filters and paging\r\n            \r\n- Defaults to **today** in `Europe/Copenhagen`. Both dates are inclusive; the maximum interval is **367 days**.\r\n- An explicit `period` replaces the date filter.\r\n- Sorted newest first, then by location and unit.\r\n- `offset`: **0–100,000**. `limit`: **1–200**, default **50**. Responses are not cached.\r\n            \r\n### Settlement periods\r\n            \r\n- The latest **100 closed period IDs** come from bank-level **LogA**.\r\n- With location-limited access, each offered period must also contain an authorized **Log1** posting.\r\n- Period **0** remains explicitly selectable. Any nonnegative period can be requested explicitly.\r\n            \r\n### Amounts and timestamps\r\n            \r\n- `amountMinor` preserves the signed Log1 amount. Totals describe **filtered movements**, not an account balance.\r\n- `MS2000` / `recordedAtUtc` is the event time, not an insertion watermark. Older postings may arrive days later.\r\n            \r\n### Receipts and retention\r\n            \r\n- `documents` groups this page only; merge further pages by `documentKey`. `items`, offsets and limits remain posting-based.\r\n- Positive DocId groups stay within the same resident, location and period. Missing/invalid IDs and payment-managed lines remain standalone.\r\n- `description` uses decoded `Kombine.Flex.FlexDto.KrumbValue.TransactionLine.ToString()` text, with numeric localization placeholders resolved by the API.\r\n- Safely displayable text-only legacy descriptions remain supported; absent DTO text uses a safe fallback. Raw JSON and payment identifiers are never exposed.\r\n- `LawAccountingYears` and `LawSurveillanceDays` come from tenant Log24 with positive manager Log7 overrides.\r\n- Expired identities become the GDPR user KID with empty names/numbers, safe description and `isAnonymized=true`.\r\n- An explicit `userKid` excludes expired entries. Amounts remain in unfiltered bank totals. Zero/missing retention means no identity retention.\r\n- `paymentKind` is Credit, ReserveRefund or Managed, or empty. Payment identifiers are never returned.\r\n- Payment-managed and expired entries cannot use ordinary reversal. No external payment workflow is invoked.\r\n            \r\n### Revisions and refresh\r\n            \r\n- `revision` fingerprints the complete filtered posting set: identities, periods and monetary totals. It is independent of `offset` and `limit`.\r\n- **Compare revisions across pages.** If they differ, discard the accumulated pages and reload them.\r\n- Use `GetBankAccountRevision` for lightweight polling.\r\n- A revision is not a cursor, authorization token or frozen snapshot. Display labels may change independently.\r\n            \r\n### Errors\r\n            \r\n**HTTP 403** keeps code `forbidden`. After tab/resource authorization, the optional `reason` identifies a missing Read permission:\r\n`missing-bank-read`, `missing-location-read`, `missing-unit-read` or `missing-user-read`.\r\n            \r\n**HTTP 503** uses these codes:\r\n            \r\n- `periods-timeout`: period SQL exceeded its **10-second** limit.\r\n- `storage-timeout`: another SQL command timed out.\r\n- `storage-text-comparison`: a collation error occurred.\r\n            \r\nAvoid automatic retry loops.",
        "operationId": "GetBankAccount",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "First inclusive date in TimeZone; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Last inclusive date in TimeZone; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "TimeZone",
            "in": "query",
            "description": "IANA/OS time zone for date filters; defaults to Europe/Copenhagen.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Period",
            "in": "query",
            "description": "Settlement period; zero is current. When supplied, replaces the date interval.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "LocationKid",
            "in": "query",
            "description": "Optional canonical location KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Optional canonical unit KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UserKid",
            "in": "query",
            "description": "Optional canonical resident KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kind",
            "in": "query",
            "description": "all, debit (negative) or credit (positive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "IncludeZero",
            "in": "query",
            "description": "Include zero postings (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IncludeBookings",
            "in": "query",
            "description": "Include Booking entries (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IncludeMonthly",
            "in": "query",
            "description": "Include Month entries (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based row offset, at most 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size 1..200, default 50.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/account/revision": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "summary": "Checks whether filtered Account2 postings changed, including late arrivals with old event timestamps.",
        "description": "### Scope and work\r\n            \r\n- Uses the same filters and permissions as `GetBankAccount`. Paging does not affect the revision.\r\n- Runs **one Log1 aggregate**, plus bounded retention-setting reads, without posting rows or label lookups.\r\n- Identical authorized scopes and filters for the same manager share a cache for at most **30 seconds** per API instance. Account and permission checks always run first.\r\n            \r\n### Polling and refresh\r\n            \r\n- Poll no faster than **every 30 seconds**, while the view is visible.\r\n- When the revision changes, reload loaded pages from offset zero. Combine only pages with equal revisions.\r\n- Labels and reversal flags can change independently; this is not a frozen snapshot.",
        "operationId": "GetBankAccountRevision",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "First inclusive date in TimeZone; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Last inclusive date in TimeZone; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "TimeZone",
            "in": "query",
            "description": "IANA/OS time zone for date filters; defaults to Europe/Copenhagen.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Period",
            "in": "query",
            "description": "Settlement period; zero is current. When supplied, replaces the date interval.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "LocationKid",
            "in": "query",
            "description": "Optional canonical location KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Optional canonical unit KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UserKid",
            "in": "query",
            "description": "Optional canonical resident KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kind",
            "in": "query",
            "description": "all, debit (negative) or credit (positive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "IncludeZero",
            "in": "query",
            "description": "Include zero postings (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IncludeBookings",
            "in": "query",
            "description": "Include Booking entries (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IncludeMonthly",
            "in": "query",
            "description": "Include Month entries (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based row offset, at most 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size 1..200, default 50.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRevisionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRevisionResponse"
                },
                "example": {
                  "revision": "9A6033B8322CC177783956FAC830E420CB9DA63B56A2E34C1C36D1AB09790D0C"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRevisionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/account/{transactionKid}/reversal": {
      "post": {
        "tags": [
          "Accounts"
        ],
        "summary": "Reverses one eligible resident consumption posting by appending a linked compensation.",
        "description": "### Access and eligible postings\r\n            \r\n- Requires **Account2**, a **bank-wide grant**, **Bank/User Write** and **Location/Unit Read**.\r\n- Supports recognized consumption with resident IDs and internal tags.\r\n- Payment transfers, anonymous/guest entries, monthly transfers, credits and unknown transaction types are unavailable.\r\n- No external payment provider is called.\r\n            \r\n### Transaction and delivery\r\n            \r\n- An InnoDB transaction locks and revalidates the original posting, rejects repeated reversal with **HTTP 409**, and queues `Log2 SyncUsers`.\r\n- The returned posting is **queued locally**; hardware delivery is not confirmed.\r\n- **Never automatically retry an uncertain write.**",
        "operationId": "ReverseBankAccountEntry",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "transactionKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AccountEntryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountEntryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountEntryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/addresses/{kid}": {
      "get": {
        "tags": [
          "Addresses"
        ],
        "summary": "Read the object's own address, coordinate pair, provenance and concurrency revision.",
        "description": "Send a canonical Bank, Location, Unit or resident User KID from this site; Tenant is excluded.\r\nRequires active manager credentials, an assigned Tab (Users2 for residents), a matching resource grant,\r\nBank Read and the object's Read permission; Unit also requires Location Read.\r\nBank and User require bank-wide or tenant-wide grants. Objects and parents must exist and not be deleted.\r\nDisabled locations require a tenant-wide grant. No parent address is inherited.\r\nLatitude and longitude are nullable integer millionths of a degree; 0 is a valid coordinate.\r\nAutoLatitudeLongitude 1..12 is the UTC month of a successful lookup; 30 means manual.\r\nUse revision as expectedRevision in every write. HTTP 404 covers missing and invisible objects.",
        "operationId": "GetObjectAddress",
        "parameters": [
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Addresses"
        ],
        "summary": "Save Address and Zip together and resolve automatic coordinates once if either field changes.",
        "description": "Requires GetObjectAddress access plus the object's Write permission, freshly rechecked inside both transactions.\r\nExample: { \"address\": \"Bjerregade 5\", \"zip\": \"8722\", \"expectedRevision\": \"revision from GetObjectAddress\" }.\r\nAddress is limited to 512 characters, zip to 64; both strings are required and may be empty to clear them.\r\nTrims outer whitespace. Unchanged inputs do not call Google. An incomplete address skips coordinate lookup.\r\nBare zip triggers one postal-city lookup for the trusted site's tenant, also in manual mode:\r\nTeam, Nortec and Electrolux use DK (four digits); Washco uses GB (full alphanumeric postcode);\r\nFinelec uses FI (five digits). Other tenants skip postal completion. Clients cannot select the country.\r\nAn exact, unambiguous result is appended to zip, for example \"7470 Karup J\"; existing city text is preserved.\r\nMissing, ambiguous or failed postal results retain the input. This lookup never changes manual coordinates.\r\nWhen the postal result lacks a city, the full address lookup may supply one with matching postal code and country.\r\nIn manual mode this fallback updates Zip only, retaining the coordinate pair and provenance.\r\nThere are at most two Google requests: postal completion followed by automatic coordinate lookup; neither is retried.\r\nExisting automatic coordinates are cleared and provenance is set to 0 before the Google request.\r\nSuccess inserts Latitude, Longitude and the UTC month atomically. Failure leaves automatic coordinates empty.\r\nManual provenance 30 preserves coordinates and skips coordinate lookup. Concurrent edits supersede the provider result.\r\nHTTP 200 confirms the saved state; inspect outcome for Success, Unchanged, IncompleteAddress,\r\nManualCoordinatesPreserved, NoResult, TransientFailure, PermanentFailure, NotConfigured or Superseded.\r\nStorage uses bank Log2 (Bank/Location/Unit) or Log7 (User), with Sync=0 and append-only history.\r\nNo automatic retries. On 409 reload. After a timeout, lost response or 503, read back before retrying:\r\nthe address transaction may already have committed. Provider failure does not undo a saved address.",
        "operationId": "UpdateObjectAddress",
        "parameters": [
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateObjectAddressRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateObjectAddressRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateObjectAddressRequest"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/addresses/{kid}/lookup": {
      "post": {
        "tags": [
          "Addresses"
        ],
        "summary": "Explicitly look up the current address, replacing manual coordinates only on success.",
        "description": "Same access and Write permission as UpdateObjectAddress. Send { \"expectedRevision\": \"current revision\" }.\r\nOne Google request at most. Automatic coordinates are cleared first; manual coordinates survive failure.\r\nFor a Location whose Address is blank, use its own Name plus Zip as the lookup input.\r\nOnly a successful result inserts Name into Address together with the coordinate pair and UTC month.\r\nName-based failures preserve the prior values; missing/invalid Name or Zip returns IncompleteAddress.\r\nA concurrent rename supersedes the name-based result, just like a concurrent address edit.\r\nA concurrent edit returns Superseded without overwriting the newer values. Outcome and errors follow UpdateObjectAddress.\r\nThis is the deliberate retry operation for an unchanged address; no background retry is scheduled.",
        "operationId": "LookupObjectCoordinates",
        "parameters": [
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ObjectAddressRevisionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ObjectAddressRevisionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ObjectAddressRevisionRequest"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/addresses/{kid}/coordinates": {
      "put": {
        "tags": [
          "Addresses"
        ],
        "summary": "Save manual Latitude and Longitude atomically with AutoLatitudeLongitude=30.",
        "description": "Same access and Write permission as UpdateObjectAddress. Send integer millionths of degrees, never decimal degrees.\r\nExample: { \"latitude\": 55771181, \"longitude\": 9697176, \"expectedRevision\": \"current revision\" }.\r\nLatitude range is -90000000..90000000; longitude -180000000..180000000. Both are required.\r\nManual coordinates survive future address edits. LookupObjectCoordinates can deliberately replace them.\r\nReturns ManualCoordinatesSaved on success. Errors and read-back advice follow UpdateObjectAddress.",
        "operationId": "SetObjectCoordinates",
        "parameters": [
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetObjectCoordinatesRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SetObjectCoordinatesRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SetObjectCoordinatesRequest"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/addresses/{kid}/provenance": {
      "put": {
        "tags": [
          "Addresses"
        ],
        "summary": "Change AutoLatitudeLongitude without changing the coordinate pair or making a Google request.",
        "description": "Same access and Write permission as UpdateObjectAddress. Send value and expectedRevision.\r\nSupported values: 0 (unknown), 1..12 (successful lookup month), 13 (legacy pending), 20 (legacy failed), 30 (manual).\r\nValues 1..12 require an existing valid coordinate pair. Manual (30) is allowed before coordinates exist.\r\nSelecting 13 does not call Google or enqueue a retry.\r\nOnly 30 protects coordinates against automatic lookup on subsequent address changes.\r\nExample: { \"value\": 30, \"expectedRevision\": \"current revision\" }. Returns ProvenanceSaved.",
        "operationId": "SetObjectCoordinateProvenance",
        "parameters": [
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetObjectCoordinateProvenanceRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SetObjectCoordinateProvenanceRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SetObjectCoordinateProvenanceRequest"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectAddressResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/assistant/query": {
      "post": {
        "tags": [
          "Assistant"
        ],
        "summary": "Ask the portal assistant to discover and combine approved read operations.",
        "description": "Sends the question, supplied visible history and relevant authorized API results to OpenAI.\r\nWith live diagnostics enabled, the current question text is recorded once in the authorized\r\nprocess-local buffer after session revalidation, before model use. Questions are not sent to Logz.io.\r\nHistory, answers and bearer credentials are not included in this log event.\r\nRequires server-side configuration. The current manager session is revalidated before model use;\r\neach business read independently enforces its existing Tab/KID/Read permissions. No special agent rights.\r\nquestion: 1–2000 characters. history: at most 12 user/assistant messages, 8000 characters each,\r\n20000 total. History is untrusted context; no server-side conversation is retained. Accept-Language selects\r\nthe default answer language. Response answer is plain text. operations lists attempted business reads;\r\nlinks contains up to 20 bank/location links derived from successful authorized results.\r\nEach link includes kid/path, optional name, canonical parent bankKid and ready-to-render iconKid.\r\nThe portal uses this metadata to add the clicked object to the local workspace; access is rechecked on navigation.\r\nAt most 8 reads, pages capped at 50, 48000 bytes per result and 120 seconds per question.\r\nAvailable reads: SearchBanks, SearchLocations, SearchUsers, GetSearchBank, GetBankLocations,\r\nGetLocations, GetLocationUnits, GetTenantStatus. Missing access, partial sources and truncation must not\r\nbe interpreted as empty/healthy data. Generated answers can be wrong; verify the underlying records.\r\nBusiness tools are discovered and called through the tenant API's MCP interface, using the current\r\nmanager bearer session. The host exposes only the eight approved read-only MCP tools and forwards\r\ntheir JSON input schemas to the model; credentials stay in server-side HTTP headers. Activation-code\r\nand Visma service-key fields are withheld from chat, including when the manager could view them in the portal.\r\nReviewed AGENTS.md instructions and three named skills are packaged with the API. Skill loading uses\r\nthe same model-turn budget and grants no extra permissions. The balance skill explains that balance\r\nand account-transaction reads are not currently in the approved chat catalogue.\r\n400 invalid input; 401 invalid/revoked session; 403 session denied; 429 six questions/minute per manager\r\nor global capacity exhausted; 503 assistant-not-configured/provider unavailable/deadline. Assistant\r\nfailures have a code extension; middleware authentication, validation and throttling retain their normal\r\nerror format. No automatic retries. Responses application-state storage is disabled with store=false.",
        "operationId": "AskPortalAssistant",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssistantRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AssistantRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AssistantRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AssistantResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssistantResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssistantResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/export-count": {
      "get": {
        "tags": [
          "BankDirectory"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetBankExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bankType",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks": {
      "get": {
        "tags": [
          "BankDirectory"
        ],
        "summary": "List authorized bank identities for Banks2 with selected metadata and stable global ordering.",
        "description": "Requires an active manager, Banks2 (5), Bank Read and site grants. Location grants reveal only\r\n            parent bank identity. Reads bank-level Log24 only. Site-wide managers can include disabled and deleted banks;\r\n            limited grants require Enabled=1 and deletions within RetentionDays. enabledOnly requires Enabled=1 and Deleted=0.\r\n            Missing Deleted means zero. Malformed states are excluded from active/limited views.\r\n            filter searches name/settings or an exact bank KID/code, at most 128 characters. bankType optionally adds an exact Credit/Cash match for localized UI searches.\r\n            fields selects bankType, bankActivationCode, exportFormat, settlementEmails, settlementDays, bankDays, cluster, hardware.\r\n            sort accepts name or any optional field; direction=asc or desc. Code ordering is numeric using the canonical codec.\r\n            pageSize is 1–250 and may change between pages; all other cursor options must remain unchanged. Keep all options unchanged with the protected, manager/scope-bound 15-minute cursor.\r\n            Concurrent edits may move rows between pages. 400 invalid query/cursor; 401 revoked session; 403 missing\r\n            tab/read/scope; 503 storage unavailable. No-store. Bank-wide fields require whole-bank scope.\r\n            Activation code display/search/sort additionally requires whole-tenant scope and Bank Create; unauthorized values are null.",
        "operationId": "GetBanks",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bankType",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BankDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankDirectoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/active-count": {
      "get": {
        "tags": [
          "BankDirectory"
        ],
        "summary": "Count accessible active banks for the Banks2 navigation icon.",
        "description": "Same session, tab and Bank Read requirements as GetBanks. Counts bank-level Log24 identities with\r\n            Enabled exactly 1 and Deleted zero (missing Deleted defaults to zero). Independent of filtering and paging.\r\n            Returns count and a ready-to-render iconKid. No-store. 401 invalid session, 403 denied, 503 unavailable.",
        "operationId": "GetActiveBankCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveBankCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveBankCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveBankCountResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/documents": {
      "get": {
        "tags": [
          "BankDocuments"
        ],
        "summary": "Search WashDoc document identities by location, unit and time without loading measurements.",
        "description": "### Access\r\nActive manager bearer, at least one of WashDoc1/2/3, Location Read and Unit Read, and a matching resource grant.\r\nLocation-only grants and RetentionDays restrict both results and filter choices before paging. KIDs must be canonical and site-bound.\r\n### Filters and ordering\r\nOptional locationKid and unitKid must belong to the requested bank; unitKid also selects its location.\r\nRepeat unitKids to select multiple canonical units (maximum 255); choices are intersected before paging/counting.\r\ndate=yyyy-MM-dd selects the whole UTC date and all earlier history since 2000; do not combine it with from/through.\r\nsearch matches an exact numeric Doc ID or canonical document KID within the selected scope.\r\nsort=activity or documentId, direction=asc or desc. Defaults remain activity descending.\r\nfrom/through are inclusive ISO 8601 timestamps with an explicit UTC offset (default: last 24 hours, maximum: 31 days).\r\nA document matches when a tagged Cycle setting occurs inside that interval. lastActivityUtc is its latest matching Cycle timestamp,\r\nnot necessarily the document's start or end. Open its table for the complete interval and completion status.\r\nNewest matching activity first, then location/unit/document identity. limit 1–100 (default 25), offset 0–100000, hasMore indicates another page.\r\nNo total count or measurement queries. Use GetBankDocumentsCount separately. Live changes can shift offset pages; reset offset to refresh the list.\r\n### Limits and errors\r\nAt most 1000 visible locations, 5000 visible/discoverable units and 35000 unit-setting rows per search; narrow by location on 422.\r\n400 invalid filters, 401 inactive session, 403 missing access, 404 hidden/missing filter object, 422 oversized scope, 503 storage unavailable/busy.\r\nTwelve-second storage deadline; no response cache. Filter choices include only currently visible units with Log24 metadata.",
        "operationId": "GetBankDocuments",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "LocationKid",
            "in": "query",
            "description": "Canonical location KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Date",
            "in": "query",
            "description": "UTC date yyyy-MM-dd. When supplied, selects that complete day and earlier history since 2000; cannot combine with from/through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "description": "Exact numeric Doc ID or canonical document KID within the selected scope.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKids",
            "in": "query",
            "description": "Repeated canonical unit KIDs, maximum 255; omitted selects all visible units. Applied before paging/counting.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "Sort",
            "in": "query",
            "description": "activity (default) or documentId; ties use location/unit/document identity.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Direction",
            "in": "query",
            "description": "asc or desc (default).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Canonical unit KID in this bank; also restricts the location.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "Inclusive ISO 8601 start with an explicit UTC offset; defaults to 24 hours before through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Inclusive ISO 8601 end with an explicit UTC offset; defaults to now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based offset, up to 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size, 1–100; defaults to 25.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BankDocumentPage"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankDocumentPage"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankDocumentPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/documents/count": {
      "get": {
        "tags": [
          "BankDocuments"
        ],
        "summary": "Count WashDocs across the authorized bank scope, without loading document pages or measurements.",
        "description": "Same access, date/search/locationKid/unitKids filters and visibility checks as GetBankDocuments. Counts distinct location/unit/document identities. Storage deadline twelve seconds; 422 for oversized scope, 503 for unavailable storage.",
        "operationId": "GetBankDocumentsCount",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "LocationKid",
            "in": "query",
            "description": "Canonical location KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Date",
            "in": "query",
            "description": "UTC date yyyy-MM-dd. When supplied, selects that complete day and earlier history since 2000; cannot combine with from/through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "description": "Exact numeric Doc ID or canonical document KID within the selected scope.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKids",
            "in": "query",
            "description": "Repeated canonical unit KIDs, maximum 255; omitted selects all visible units. Applied before paging/counting.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "Sort",
            "in": "query",
            "description": "activity (default) or documentId; ties use location/unit/document identity.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Direction",
            "in": "query",
            "description": "asc or desc (default).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Canonical unit KID in this bank; also restricts the location.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "Inclusive ISO 8601 start with an explicit UTC offset; defaults to 24 hours before through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Inclusive ISO 8601 end with an explicit UTC offset; defaults to now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based offset, up to 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size, 1–100; defaults to 25.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/documents": {
      "get": {
        "tags": [
          "BankDocuments"
        ],
        "summary": "List WashDocs for one authorized location, optionally selecting one or several units.",
        "description": "Active manager, a WashDoc tab, Location Read, Unit Read and a matching site-bound resource grant. date=yyyy-MM-dd includes that entire UTC date and earlier history. Repeat unitKids with canonical unit KIDs in this location (maximum 255); omitted means all visible units. search accepts an exact numeric Doc ID or canonical document KID. sort=activity or documentId, direction=asc or desc; offset 0–100000, limit 1–100. RetentionDays and selected units are applied before paging. Filter choices include all authorized visible units. No measurement reads. 400 invalid scope/filters, 403 denied, 404 hidden location/unit, 422 oversized scope, 503 busy/unavailable.",
        "operationId": "GetLocationDocuments",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Date",
            "in": "query",
            "description": "UTC date yyyy-MM-dd. When supplied, selects that complete day and earlier history since 2000; cannot combine with from/through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "description": "Exact numeric Doc ID or canonical document KID within the selected scope.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKids",
            "in": "query",
            "description": "Repeated canonical unit KIDs, maximum 255; omitted selects all visible units. Applied before paging/counting.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "Sort",
            "in": "query",
            "description": "activity (default) or documentId; ties use location/unit/document identity.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Direction",
            "in": "query",
            "description": "asc or desc (default).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Canonical unit KID in this bank; also restricts the location.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "Inclusive ISO 8601 start with an explicit UTC offset; defaults to 24 hours before through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Inclusive ISO 8601 end with an explicit UTC offset; defaults to now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based offset, up to 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size, 1–100; defaults to 25.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BankDocumentPage"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankDocumentPage"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankDocumentPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/documents/count": {
      "get": {
        "tags": [
          "BankDocuments"
        ],
        "summary": "Count distinct WashDocs for the selected location and unit choices.",
        "description": "Uses the same access, date, search and repeated unitKids filters as GetLocationDocuments. Counts location/unit/document identities without traversing pages or reading measurements. No response cache.",
        "operationId": "GetLocationDocumentsCount",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Date",
            "in": "query",
            "description": "UTC date yyyy-MM-dd. When supplied, selects that complete day and earlier history since 2000; cannot combine with from/through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "description": "Exact numeric Doc ID or canonical document KID within the selected scope.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKids",
            "in": "query",
            "description": "Repeated canonical unit KIDs, maximum 255; omitted selects all visible units. Applied before paging/counting.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "Sort",
            "in": "query",
            "description": "activity (default) or documentId; ties use location/unit/document identity.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Direction",
            "in": "query",
            "description": "asc or desc (default).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Canonical unit KID in this bank; also restricts the location.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "Inclusive ISO 8601 start with an explicit UTC offset; defaults to 24 hours before through.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Inclusive ISO 8601 end with an explicit UTC offset; defaults to now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based offset, up to 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size, 1–100; defaults to 25.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/icons": {
      "get": {
        "tags": [
          "BankIcons"
        ],
        "summary": "Resolve up to eight bank icons with their authorized units' combined status.",
        "description": "Repeat kid with canonical bank KIDs from this site. Requires an active manager, assigned Tab,\r\nBank Read, Location Read, Unit Read and a matching resource grant. A location-only grant includes only that location.\r\nLocation and unit RetentionDays visibility applies; disabled locations require access to all banks.\r\nAny included Alive.Offline=1 sets offline=true and Kid.Icons[1]=eIcon.close. A nonempty set entirely\r\nknown Offline=0 sets offline=false and eIcon.check. Empty/incomplete status is null unless some unit is offline.\r\nUnits are discovered in Log24; orphan Alive rows do not contribute. No writes.\r\nPer-item 403/503 returns no icon/status; 400 invalid/foreign/oversized input, 401 expired session, 503 session storage failure.\r\nThe API returns opaque iconKid, preserving primary icon and bank number text. Use it unchanged with GetIconFromSet.\r\nRead visible banks only, deduplicate and refresh at most every ten seconds, pausing hidden pages.\r\nStatus is cached ten seconds per authorized location set, location/label metadata sixty seconds. HTTP is no-store.\r\nBounded to 65,536 units per bank and 128 locations per SQL batch; oversized or ambiguous data fails, never partial online.",
        "operationId": "GetBankIcons",
        "parameters": [
          {
            "name": "kid",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BankIconsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankIconsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankIconsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/locations": {
      "get": {
        "tags": [
          "BankLocations"
        ],
        "summary": "List location names, icons, status and canonical KIDs in bank overview order (location number).",
        "description": "### Access and visibility\r\n            \r\n- Requires an active manager, at least one assigned **Tab**, **Location Read** and a matching site/bank/location grant.\r\n- Location-only managers see only their granted locations.\r\n- An explicit site-wide grant lists all location states, including disabled locations and deletions outside RetentionDays.\r\n- Other grants require Enabled exactly 1 and deletion within **RetentionDays**. Missing Deleted means zero;\r\n  zero retention hides all deleted locations, and malformed/future deletions are hidden.\r\n            \r\n### Results and cache\r\n            \r\n- Returns names, icons, enabled, deleted, deletedAt and canonical KIDs in **location-number order**.\r\n- Enabled is true only for stored Enabled exactly 1; missing or invalid values mean false.\r\n- Deleted indicates a positive Deleted MS2000 value; deletedAt is its UTC timestamp (null for zero or an unrepresentable value).\r\n- For status display, disabled takes precedence over deleted, then active. Status never grants access.\r\n- Locations lacking all Name, Icon, Deleted and Enabled settings cannot be discovered. Missing or invalid icons use `house`.\r\n- One bank-scoped query is cached for **60 seconds**; authorization is checked on every request.\r\n- No pagination or total-count query.",
        "operationId": "GetBankLocations",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankLocationStatusResponse"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankLocationStatusResponse"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankLocationStatusResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/banks": {
      "get": {
        "tags": [
          "BankSearch"
        ],
        "summary": "Search current bank names and settlement emails; literal case-insensitive substring matching.",
        "description": "### Access and identifiers\r\n            \r\n- Requires at least one current **Tab**, **Bank Read** and a matching grant. A location grant allows discovery of its parent bank only.\r\n- Only **BankId ≥ 1000** is searchable.\r\n- Accepts an exact canonical or readable KID. An omitted tenant is resolved from trusted site configuration; `matchedSetting` is `Kid`.\r\n- Cross-tenant or inaccessible identities return no results.\r\n            \r\n### Text search and results\r\n            \r\n- Searches current bank **Name** and **SettlementEmails** using literal, case-insensitive substrings.\r\n- `q`: **2–128 trimmed characters**. At most **50 rows**; `hasMore` asks the caller to refine the query.\r\n- Current Name, Icon and SettlementEmails settings come from **Log24**, supporting JSON and legacy text.\r\n- Uses a **60-second scoped cache**.",
        "operationId": "SearchBanks",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/bank-activation": {
      "get": {
        "tags": [
          "BankSearch"
        ],
        "summary": "Decode a bank activation code and resolve its name and icon from the cached Log24 bank catalogue.",
        "description": "### Access and lookup\r\n            \r\n- Uses the same authorization as `SearchBanks`. Only bank codes for this site's tenant and granted banks match.\r\n- Invalid or out-of-scope codes skip the bank lookup. Missing banks return an empty list.\r\n- Resolves name and icon from the cached **Log24 bank catalogue**; `zip` remains empty.\r\n            \r\n### Shared activation-code rate limit\r\n            \r\n- Maximum **5 requests per 10 minutes** and **20 per hour**, per manager in this tenant API process, across tokens and IP addresses.\r\n- The bank, location and resident activation-code endpoints share this quota. **All attempts count**, including malformed and successful codes.\r\n- **HTTP 429** includes `Retry-After` in seconds. Do not retry early.",
        "operationId": "SearchBankActivation",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/banks/{bankKid}": {
      "get": {
        "tags": [
          "BankSearch"
        ],
        "summary": "Resolve a search result before opening its bank overview, including tenant-wide managers.",
        "description": "### Access and lookup\r\n            \r\n- Resolves one canonical bank KID on this site before opening the bank overview, including for tenant-wide managers.\r\n- Requires the same active session, current Tab, **Bank Read** and matching grant as `SearchBanks`.\r\n- Only **BankId ≥ 1000** is discoverable. A stored search result is not an access grant.\r\n            \r\n### Result\r\n            \r\n- Returns the matching bank from the scoped catalogue, or empty items when absent or inaccessible.\r\n- Invalid or cross-tenant bank KIDs return **HTTP 400**.",
        "operationId": "GetSearchBank",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/export-count": {
      "get": {
        "tags": [
          "BankUsers"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetBankUserExportCount",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deleted",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users": {
      "get": {
        "tags": [
          "BankUsers"
        ],
        "summary": "Read one page of users for a bank.",
        "description": "### Access and visibility\r\n            \r\n- Requires **Users2 (53)**, **User Read** and a matching tenant/bank/location grant.\r\n- An exact **userKid** lookup also accepts **UserFinder1 (77)** instead of Users2; bulk lists still require Users2.\r\n- Location-only grants include **Access** and **NoAccess** associations; other locations are removed from the response.\r\n- Ordinary users only, including `eUserId.UsersLast`. Deleted users follow **RetentionDays**.\r\n- `email` is the current Log7 `eSetting.Email` (2800), decoded from JSON or legacy plain text.\r\n- `sms` is the current Log7 `eSetting.SMS` number, decoded without changing its format. Missing email/SMS values are empty.\r\n            \r\n### Paging\r\n            \r\n- `pageSize`: **1–250**, default **25**. Copy `previousCursor` or `nextCursor` unchanged into `cursor`.\r\n- Cursors are shareable positions, not credentials.\r\n- Keep filters, sort and direction unchanged while using a cursor. Restart **without a cursor** when changing them.\r\n            \r\n### Ordering\r\n            \r\n- `sort`: `identity` (legacy default, ascending only), `number`, `name`, `location` or `deleted`.\r\n- `direction`: `asc` or `desc`. User identity breaks ties.\r\n- Number orders numeric values before text. Text comparison is ordinal and case-insensitive.\r\n- Location uses the lowest permitted Access/NoAccess location. Missing values and not-deleted users sort first in ascending order.\r\n- Sorted mode uses a **four-setting index cached for one minute** and reads details only for the selected page.\r\n            \r\n### Text and identity filters\r\n            \r\n- `filter`: optional case-insensitive substring in **Number OR Name**, at most **200 characters**, with surrounding whitespace trimmed.\r\n- Wildcards: `*` matches zero or more characters; `?` matches one. Other symbols are literal.\r\n- Filtering precedes paging and uses the shared sorting index.\r\n- `userKid` selects exactly one ordinary bank user and cannot be combined with `filter` or `cursor`.\r\n- The same Tab, scope, operation and retention checks apply. Missing or inaccessible users return empty items.\r\n            \r\n### Location and deletion filters\r\n            \r\n- `locationKid` filters an authorized location in the same bank, including Access and NoAccess associations.\r\n- `deleted`: `all` (default), `active`, `deleted` or `no-access`.\r\n- `no-access` means no recorded Access in any manager-visible location. Empty lists and NoAccess-only lists match; hidden locations do not affect the result.\r\n- Existing visibility and deletion retention still apply. `locationKid` remains an additional association filter.\r\n            \r\n### Cache and scan limits\r\n            \r\n- Every request rechecks access. Data may be cached for **60 seconds**. No total count is queried.\r\n- Legacy identity mode examines at most **1,000 candidates**. `scanLimitReached` may accompany an empty or short page; follow `nextCursor` to continue.\r\n- Concurrent changes are not a transactionally frozen snapshot.",
        "operationId": "GetBankUsers",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deleted",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BankUsersResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankUsersResponse"
                },
                "example": {
                  "items": [
                    {
                      "kid": "3E7Q3Co2Ab3E9h",
                      "name": "Example user",
                      "number": "A-1001",
                      "email": "resident@example.invalid",
                      "sms": "+1 202-555-0123",
                      "deletedAt": null,
                      "locations": [ ],
                      "tags": [ ],
                      "attributes": [ ]
                    }
                  ],
                  "previousCursor": null,
                  "nextCursor": null,
                  "scanLimitReached": false
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankUsersResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Create a resident. Requires bank-wide Users2/User Create. Action must be create. No hardware access is assigned automatically.",
        "description": "### Access and request\r\n            \r\n- Requires an active manager, **Users2**, **User Read**, **User Create** and a **bank-wide grant**.\r\n- `action` must be `create`. The canonical bank KID must belong to this site.\r\n- No hardware access is assigned automatically.\r\n            \r\n### Result and synchronization\r\n            \r\n- **HTTP 201:** returns authoritative resident workspace details and a revision.\r\n- Successful creation schedules the existing backend synchronization; it is not instant hardware confirmation.\r\n- Resident data and synchronization use Log tables exclusively. No notification or billing operation is executed.\r\n- Disabled, unconfigured or nontransactional storage returns **HTTP 503**.",
        "operationId": "CreateBankUser",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCommandRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCommandRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UserCommandRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/bookings": {
      "get": {
        "tags": [
          "Bookings"
        ],
        "summary": "Lists the latest nonsuperseded Log5 event for each location/unit/resident/start.",
        "description": "### Access\r\n            \r\n- Requires **Bookings1**, **Location/Unit/User Read** and matching bank or location grants.\r\n- Denial reads no booking data. **HTTP 403** keeps code `forbidden`; after tab/resource authorization, optional `reason` identifies `missing-location-read`, `missing-unit-read` or `missing-user-read`.\r\n            \r\n### Dates and events\r\n            \r\n- Inclusive local date range, defaulting to UTC today minus **7 days** through plus **90 days**; maximum **367 dates**.\r\n- Weekly positions (**0–10,079**) are returned separately, never converted to UTC. `recordedAtUtc` is the event time.\r\n- AUT/isy events are excluded as in Bookings1. Filters and pagination run after selecting the latest event.\r\n            \r\n### Search and paging\r\n            \r\n- Search matches stored resident name/number. Only authorized location/unit filter labels are returned.\r\n- `limit`: **1–200**, default **50**. `offset`: **0–100,000**.\r\n- Stable start/location/unit/user order. No total-count query or cache.",
        "operationId": "GetBankBookings",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "through",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "unitKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "all"
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string",
              "default": ""
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BookingsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookingsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/bookings/{bookingKid}/commands": {
      "post": {
        "tags": [
          "Bookings"
        ],
        "summary": "Appends a cancellation or restoration, preserving history and requesting backend synchronization.",
        "description": "### Command and access\r\n            \r\n- `action` is `cancel` or `restore`.\r\n- Requires **Bookings1**, **Location/User Read**, **Unit Write** and the event's location grant.\r\n- The booking KID identifies the **exact event reviewed** by the caller. Stale or repeated commands return **HTTP 409**.\r\n            \r\n### Transaction and restoration\r\n            \r\n- Current events are locked and rechecked in one **InnoDB transaction**. Do not retry automatically.\r\n- Restoration rejects overlapping active reservations.\r\n- Weekly restorations are unsupported. Active weekly schedules conservatively block restoration on their unit.\r\n- `sync=false` means **queued**, not confirmed by the controller.",
        "operationId": "ExecuteBankBookingCommand",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bookingKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BookingCommand"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/BookingCommand"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/BookingCommand"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BookingResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookingResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookingResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/nearest-location": {
      "get": {
        "tags": [
          "Camera"
        ],
        "summary": "Resolve the nearest writable location within 100 metres for tenant-level camera capture.",
        "description": "Requires Camera1 and Location Read/Write within the trusted tenant scope. Only enabled, retained locations with valid stored coordinates qualify. GPS accuracy must be at most 100 metres. No bank or unit is returned. Returns 404 if none qualify, 409 if the two nearest locations cannot be distinguished within GPS accuracy, 400 for invalid coordinates and 503 for an incomplete lookup. The returned location must still pass normal capture authorization.",
        "operationId": "GetCameraNearestLocation",
        "parameters": [
          {
            "name": "latitude",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "longitude",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "accuracyMeters",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraResourceResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraResourceResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraResourceResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/resource": {
      "get": {
        "tags": [
          "Camera"
        ],
        "summary": "Read the display identity of one authorized camera resource.",
        "description": "Requires an active manager, Camera1, the exact resource's Read permission, site-bound resource scope and retention visibility. A location does not require Unit Read; a unit does not require Location Read. Returns resourceKid, name, iconKid and requiresProximityCheck. Locations and units include nullable latitude/longitude in decimal degrees; units inherit the location coordinates. Banks have no proximity check. These coordinates support an advisory 100-metre warning, not authorization. Invalid or cross-tenant KIDs return 400, invalid sessions 401, denied access 403, missing/invisible resources 404 and unavailable storage 503.",
        "operationId": "GetCameraResource",
        "parameters": [
          {
            "name": "resourceKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraResourceResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraResourceResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraResourceResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/availability": {
      "get": {
        "tags": [
          "Camera"
        ],
        "summary": "Check the lazy local camera tab and capture permission for one exact resource.",
        "operationId": "GetCameraAvailability",
        "parameters": [
          {
            "name": "resourceKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraAvailabilityResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraAvailabilityResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraAvailabilityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/prepare": {
      "post": {
        "tags": [
          "Camera"
        ],
        "summary": "Prepare a bounded, immutable capture plan including optional weather.",
        "description": "Requires Camera1 plus resource Read and Write. Hash original bytes with SHA-256. For kind live-photo, provide motionLength and motionSha256 for the original QuickTime movie companion. The signed uploadToken binds both files, metadata, owner and tenant. Retain the token and identical bytes for retries; tokens expire after 24 hours. Weather failure does not prevent capture. Imported media may use capturedAtUtc from Unix epoch through five minutes ahead of server time. Declare inferred timestamps in sensorData.timestampSource and do not attach current device sensors to historical media.",
        "operationId": "PrepareCameraCapture",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CameraPrepareRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CameraPrepareRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CameraPrepareRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraPrepareResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraPrepareResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraPrepareResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Content Too Large",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera": {
      "post": {
        "tags": [
          "Camera"
        ],
        "summary": "Save camera media synchronously, or accept bounded background processing.",
        "description": "Multipart fields: uploadToken from PrepareCameraCapture and original (binary file); live-photo additionally requires motion (original JPEG plus QuickTime MOV). Every component is bounded, hashed and decoded server-side. Success confirms the full set, generated thumbnail, optional playback derivative and JSON in one private region. FRA/AMS origin filenames remain unchanged when replicated. No camera database or public storage link is used.",
        "operationId": "SaveCameraCapture",
        "parameters": [
          {
            "name": "background",
            "in": "query",
            "description": "When true, 202 acknowledges validated temporary staging only. Poll ConfirmCameraCapture with the same ticket; retain original bytes until confirmed. Host restart may require retry. Default false retains synchronous 200 confirmation.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "uploadToken",
                  "original"
                ],
                "type": "object",
                "properties": {
                  "uploadToken": {
                    "type": "string",
                    "description": "Unchanged token from PrepareCameraCapture."
                  },
                  "original": {
                    "type": "string",
                    "description": "Original captured bytes matching the prepared length and SHA-256.",
                    "format": "binary"
                  },
                  "motion": {
                    "type": "string",
                    "description": "Required only for live-photo: the original QuickTime MOV companion matching its prepared length and hash. Omit for other capture kinds.",
                    "format": "binary"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraSaveResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraSaveResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraSaveResponse"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraSaveResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraSaveResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraSaveResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Content Too Large",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "Camera"
        ],
        "summary": "List own tenant captures, or all authorized captures on one exact bank, location or unit.",
        "description": "Camera1 and resource Read are required. Both Spaces regions are queried. A degraded response is not proof of an empty collection. Pass nextCursor unchanged with the same resourceKid; pages can be empty after authorization filtering. Captures are ordered newest first. Nullable bankName, locationName and unitName describe the current resource hierarchy; each name requires that object's Read permission, scope and retention visibility. Inapplicable or unauthorized names are null. Unit names resolve localized placeholders. No storage URLs or credentials are returned.",
        "operationId": "GetCameraCaptures",
        "parameters": [
          {
            "name": "resourceKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraCapturePage"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraCapturePage"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraCapturePage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/confirmation": {
      "post": {
        "tags": [
          "Camera"
        ],
        "summary": "Confirm publication of an exact prepared capture after an uncertain upload response.",
        "description": "Requires the original uploadToken, its authenticated owner and current Camera1/resource Read and Write. confirmed=false is not proof of failure; retain the original bytes and ticket for retry. No media is uploaded by this operation.",
        "operationId": "ConfirmCameraCapture",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CameraConfirmationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CameraConfirmationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CameraConfirmationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CameraConfirmationResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraConfirmationResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CameraConfirmationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/{id}/content": {
      "get": {
        "tags": [
          "Camera"
        ],
        "summary": "Stream one capture component through the API, with current resource authorization.",
        "description": "id is an opaque, short-lived identity from GetCameraCaptures. part is original, thumbnail, metadata, motion, motion-playback, playback or preview. QuickTime and WebM originals have a separate H.264/AAC playback part; Live Photo motion uses motion-playback. Missing copies fall back to the other region. No redirects or public Spaces links.",
        "operationId": "GetCameraCaptureContent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "part",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "original"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Optional single byte range, for example bytes=0-1023. Valid ranges return 206; invalid ranges return 416.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/quicktime": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "Partial Content",
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/quicktime": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/camera/recent/{id}/metadata": {
      "get": {
        "tags": [
          "Camera"
        ],
        "summary": "Read private capture metadata for a public recent-photo thumbnail.",
        "description": "Use the opaque id from the public thumbnail URL. Requires an active manager, Camera1, resource Read, scope and retention visibility. The public thumbnail ticket alone grants no metadata access. Returns 400 for invalid/expired tickets, 401/403 for denied access, 404 for missing metadata and 503 for unavailable storage.",
        "operationId": "GetRecentCameraPhotoMetadata",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "text/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/account/export": {
      "get": {
        "tags": [
          "Downloads"
        ],
        "summary": "Downloads the complete filtered selection as CSV or a genuine Excel workbook.",
        "description": "### Scope and limits\r\n            \r\n- Uses the same permissions and filters as `GetBankAccount`. Pagination is ignored.\r\n- Maximum **10,000 rows** and **4 million description characters**.\r\n- Oversized selections fail with **HTTP 413**, `data-limit`, instead of returning a truncated file.\r\n            \r\n### File contents\r\n            \r\n- Downloads CSV or a genuine Excel workbook; spreadsheet formulas are neutralized.\r\n- Money uses signed minor units; dates use **UTC**.\r\n- The same retention rules, user filtering and safe descriptions as GetBankAccount apply; column names are unchanged.\r\n- Headers and identifiers are stable and language-independent.",
        "operationId": "ExportBankAccount",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "From",
            "in": "query",
            "description": "First inclusive date in TimeZone; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "Through",
            "in": "query",
            "description": "Last inclusive date in TimeZone; defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "TimeZone",
            "in": "query",
            "description": "IANA/OS time zone for date filters; defaults to Europe/Copenhagen.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Period",
            "in": "query",
            "description": "Settlement period; zero is current. When supplied, replaces the date interval.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "LocationKid",
            "in": "query",
            "description": "Optional canonical location KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UnitKid",
            "in": "query",
            "description": "Optional canonical unit KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "UserKid",
            "in": "query",
            "description": "Optional canonical resident KID in this bank.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kind",
            "in": "query",
            "description": "all, debit (negative) or credit (positive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "IncludeZero",
            "in": "query",
            "description": "Include zero postings (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IncludeBookings",
            "in": "query",
            "description": "Include Booking entries (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IncludeMonthly",
            "in": "query",
            "description": "Include Month entries (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based row offset, at most 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size 1..200, default 50.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "csv"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "text/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Content Too Large",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/export": {
      "get": {
        "tags": [
          "Downloads"
        ],
        "summary": "Download filtered residents as UTF-8 CSV, at most 10,000 residents and 4 MiB text.",
        "description": "### Access and selection\r\n            \r\n- Uses the same **Users2/User Read**, scope, retention and filter rules as `GetBankUsers`. Authorization is rechecked for every page.\r\n- `deleted` accepts `all`, `active`, `deleted` and `no-access`.\r\n- `no-access` excludes users with recorded Access in any manager-visible location.\r\n- Export is not a transactionally frozen snapshot.\r\n            \r\n### Format and limits\r\n            \r\n- **UTF-8 CSV**, semicolon delimiter, stable English column identifiers and ISO UTC dates.\r\n- Cells are quoted and protected against spreadsheet formulas.\r\n- At most **10,000 residents** and **4 MiB text**.\r\n- A limit failure returns **HTTP 422** without a partial file; narrow the filter.",
        "operationId": "ExportBankUsers",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deleted",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "all"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "number"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/settlements/{period}/download": {
      "get": {
        "tags": [
          "Downloads"
        ],
        "summary": "Downloads a ZIP with one settlement file per group and currency, plus a reconciliation manifest.",
        "description": "### Download contents\r\n            \r\n- Returns a ZIP with **one settlement file per group and currency**, plus a reconciliation manifest.\r\n- This operation never closes or changes a period.\r\n            \r\n### Formats\r\n            \r\nThe `format` value is **case-sensitive**:\r\n            \r\n- `XLS` — produces real **XLSX** files.\r\n- `ATB`, `BL`, `DEAS`, `FRUEHØJGAARD`, `HEIMSTADEN`, `LEJERBO`.\r\n- `MD90_1`, `MD90_3`, `MD90_3_minus`, `MD90_3_plus`, `MD90_3_AABKBH`.\r\n- `NAVISION`.\r\n            \r\n### Restrictions\r\n            \r\n- `MD90_3` supports banks **1001 and 1068 only**.\r\n- `NIRAS` and `ROBERT` are obsolete.\r\n- Invalid or oversized source data fails explicitly.",
        "operationId": "DownloadBankSettlement",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "XLS"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/table.csv": {
      "get": {
        "tags": [
          "Downloads"
        ],
        "summary": "Download a UTF-8 CSV table for one document.",
        "description": "### Access and data\r\nSame authorization, selection and limits as GetUnitDocumentTable. No interpolation, rounding or caching.\r\n### CSV format\r\nUTF-8 BOM, comma delimiter, quoted cells, CRLF records, MS2000 and ISO UTC columns followed by state/setting columns.\r\nEmbedded quotes/newlines are escaped. Potential formulas in nonnumeric text are prefixed with an apostrophe for spreadsheet safety.\r\nEmpty CSV cells cannot distinguish absent, null and empty text; use the JSON table when that distinction matters.",
        "operationId": "DownloadUnitDocumentCsv",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/csv": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/csv": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/csv": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/csv": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/csv": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/csv": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/table.xls": {
      "get": {
        "tags": [
          "Downloads"
        ],
        "summary": "Download an Excel 97–2003 binary .xls workbook for one document.",
        "description": "### Access and data\r\nSame authorization, selection and limits as GetUnitDocumentTable. No interpolation or caching.\r\n### Workbook\r\nGenuine BIFF8 XLS; one Document worksheet, fixed header row, MS2000 and UTC timestamps.\r\nSource values with more than 15 digits or noncanonical numeric formatting remain text, preserving their original representation.\r\nText is written as string cells, never formulas. No macros, external links, Excel installation or Office automation.",
        "operationId": "DownloadUnitDocumentXls",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/vnd.ms-excel": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/hosting/logs": {
      "get": {
        "tags": [
          "HostingLogs"
        ],
        "summary": "Read recent DigitalOcean runtime logs for a configured shared app.",
        "description": "Requires Logs1, Managers Read and whole-tenant access. Operator policy explicitly permits\r\ncross-tenant app logs for managers with this access. Logs can contain other customers.\r\nenvironment: beta/production; application: portal-api/equipment-api/portal-web. No MySQL logs.\r\nReturns up to 100 plain-text lines, a fetchedAtUtc snapshot timestamp and a truncated flag.\r\nPoll at most every 10 seconds. This is a recent snapshot, not a durable or complete log history.\r\n400 invalid selection; 401 invalid session; 403 missing Tab, Read or tenant grant;\r\n503 hosting-not-configured or hosting-unavailable. Failed reads never return stale logs.\r\nProvider tokens, signed URLs and raw transport errors are never returned. Render lines as text.\r\nRuntime logs only; build, deploy, crash and database logs are not provided by this operation.\r\nWhen continuous forwarding is enabled on the collector host, reads use its bounded runtime buffer.\r\nLogz.io delivery runs independently of readers; this response does not confirm remote delivery.",
        "operationId": "GetHostingLogs",
        "parameters": [
          {
            "name": "environment",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "beta"
            }
          },
          {
            "name": "application",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "portal-api"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/HostingLogsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostingLogsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostingLogsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/hosting/metrics": {
      "get": {
        "tags": [
          "HostingMetrics"
        ],
        "summary": "Read hosting metrics for one configured application or Managed MySQL cluster.",
        "description": "Requires an active manager, Hosting1 (81), Managers Read and a whole-tenant KID grant for this site.\r\nEvery request rechecks the bounded manager snapshot (at most 60 seconds old), before any metric cache hit.\r\nInfrastructure is shared: values cover all customers in the app, not this tenant's individual usage.\r\nenvironment is beta or production; application is portal-api, equipment-api, portal-web or mysql; hours is 1, 6 or 24.\r\nThese fixed selectors never accept tenant IDs, provider app IDs or URLs. The site owns all provider mappings.\r\nMetrics cpu/memory use percent; restarts use the provider's count series, not a calculated window total.\r\nSeries retain component/instance separation. Null samples are gaps; empty series mean no data, never zero.\r\nbandwidth.dateUtc is yesterday in UTC, independent of hours; bytes is an unsigned decimal string or null.\r\nFor mysql, metrics are cpu/memory/disk (provider cluster averages in percent) and connections (current threads,\r\ncount). Bandwidth is null. The same database may be shared by beta and production. No SQL is executed.\r\nCheck every errorCode: a partial response is HTTP 200 with hosting-source-unavailable for failed sources.\r\nAll sources failing returns 503 hosting-unavailable; disabled/missing configuration returns 503 hosting-not-configured.\r\nResults and failures are cached for 60 seconds on the API; refresh no faster than refreshAfterSeconds.\r\nFetchedAtUtc identifies the snapshot, not the latest sample. Sample timestamps may lag or be absent.\r\n400 invalid-hosting-selection; 401 revoked/invalid session; 403 missing-hosting-tab,\r\nmissing-managers-read or missing-tenant-access. No secrets or provider error bodies are returned.\r\nBrowser responses are no-store. See the integration guide's Hosting section for copyable examples.",
        "operationId": "GetHostingMetrics",
        "parameters": [
          {
            "name": "environment",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "beta"
            }
          },
          {
            "name": "application",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "portal-api"
            }
          },
          {
            "name": "hours",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 24
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/HostingMetricsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostingMetricsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostingMetricsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/installers/{installerKid}/icon": {
      "post": {
        "tags": [
          "InstallerIcons"
        ],
        "summary": "Save an installer's selected Person icon.",
        "description": "### Access and validation\r\n- Requires active manager, Installers1 (68), independent Installer Read and Write and whole-tenant access.\r\n- Rechecks the current locked manager account, credential stamp, tabs, rights and scope, and target existence\r\n  and caller RetentionDays, inside the write transaction. Manager Write alone grants nothing here.\r\n- installerKid must be canonical, from this site, with BankId=TenantId and eUserId.Installeres..InstalleresLast.\r\n- Send an exact eIcon name with eIconSubject.Person metadata and expectedRevision from GetInstaller.\r\n  Current non-Person icons may be displayed but cannot be assigned. Do not post clicks on an already selected legacy icon.\r\n            \r\n### Storage and response\r\n- Appends only eSetting.Icon to A{TenantId:D4}{TenantId:D5}.Log7 with the acting manager in TagId and database\r\n  MS2000. Verifies the trigger's A{TenantId:D4}.Log7 current value at BankId=TenantId before committing.\r\n- Serializable transaction; unchanged raw values add no history. No other installer settings or Alive change.\r\n- Update the icon and workspace only after a complete 200 response. Use its iconRevision for the next edit.\r\n- Directory indexes are invalidated locally even after uncertain outcomes; other instances may retain list\r\n  indexes for up to 60 seconds. Details are always fresh. All responses are no-store, with a 12-second deadline.\r\n            \r\n### Errors\r\n- 400 invalid-installer-kid/invalid-installer-icon; 401 revoked session; 403 missing-installers-tab,\r\n  missing-installers-read, missing-installers-write or missing-tenant-access; 404 installer-not-found.\r\n- 409 installer-icon-conflict: reread and review before another save. Revision covers the raw Icon value and row presence.\r\n- 503 installer-icon-unavailable: keep the displayed icon and reread before retrying manually. A lost response\r\n  can follow commit; never retry a mutation automatically. Database writes must be configured for the site.",
        "operationId": "SetInstallerIcon",
        "parameters": [
          {
            "name": "installerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InstallerIconRequest"
              },
              "example": {
                "icon": "angel",
                "expectedRevision": "DAC624CAD7E61C2DDF2608112A4462DC633CD8D22128F3DDFBCAD2E44294CF64"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/InstallerIconRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/InstallerIconRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerIconResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerIconResponse"
                },
                "example": {
                  "kid": "A6Q32oA6b1h",
                  "iconKid": "angel",
                  "iconRevision": "5CE7200DE215F47D73E8C782F447813306BD7DD66F0C468AD961D92D0C950FDE",
                  "availableIcons": [
                    "angel",
                    "astrologer",
                    "astronaut",
                    "athlete",
                    "baby",
                    "bicyclist",
                    "bookkeeper",
                    "boy",
                    "businessman",
                    "businessman2",
                    "businessperson",
                    "businessperson2",
                    "businessperson3",
                    "businesswoman",
                    "businesswoman2",
                    "caesar",
                    "clown",
                    "cook",
                    "criminal",
                    "delivery_man",
                    "delivery_man_parcel",
                    "devil",
                    "disability",
                    "doctor",
                    "dude1",
                    "dude2",
                    "dude3",
                    "dude4",
                    "dude5",
                    "dude6",
                    "engineer",
                    "face_scan",
                    "firefighter",
                    "genius",
                    "girl",
                    "graduate",
                    "guard",
                    "hipster",
                    "holmes",
                    "judge",
                    "lecture",
                    "magician",
                    "motorcyclist",
                    "nurse",
                    "pastor",
                    "person",
                    "pilot",
                    "policeman",
                    "policeman_bobby",
                    "pontifex",
                    "schoolboy",
                    "scientist",
                    "security_agent",
                    "senior_citizen",
                    "senior_citizen2",
                    "singer",
                    "soldier",
                    "spy",
                    "stockbroker",
                    "stockbroker2",
                    "surgeon",
                    "teacher",
                    "teacher_blackboard",
                    "terrorist",
                    "user",
                    "user_earth",
                    "user_glasses",
                    "user_headphones",
                    "user_headset",
                    "user_message",
                    "user_mobile_phone",
                    "user_monitor",
                    "user_smartphone",
                    "user_sunglasses",
                    "user_telephone",
                    "video_chat",
                    "video_chat2",
                    "woman",
                    "woman2",
                    "woman3",
                    "woman4",
                    "worker",
                    "worker2",
                    "user_mobilephone",
                    "accessibility",
                    "accessibility_new",
                    "accessible",
                    "accessible_forward",
                    "account_box",
                    "account_circle",
                    "assignment_ind",
                    "contact_page",
                    "face",
                    "face_unlock",
                    "manage_accounts",
                    "no_accounts",
                    "perm_contact_calendar",
                    "perm_identity",
                    "pregnant_woman",
                    "record_voice_over",
                    "rowing",
                    "settings_accessibility",
                    "transcribe",
                    "voice_over_off",
                    "contacts",
                    "contact_emergency",
                    "contact_mail",
                    "contact_phone",
                    "co_present",
                    "person_add_disabled",
                    "person_search",
                    "attribution",
                    "how_to_reg",
                    "remember_me",
                    "face_retouching_natural",
                    "face_retouching_off",
                    "portrait",
                    "badge",
                    "directions_run",
                    "directions_walk",
                    "person_pin",
                    "person_pin_circle",
                    "run_circle",
                    "streetview",
                    "transfer_within_a_station",
                    "support_agent",
                    "child_care",
                    "assist_walker",
                    "blind",
                    "downhill_skiing",
                    "elderly",
                    "elderly_woman",
                    "emoji_people",
                    "engineering",
                    "face_2",
                    "face_3",
                    "face_4",
                    "face_5",
                    "face_6",
                    "follow_the_signs",
                    "hiking",
                    "kayaking",
                    "kitesurfing",
                    "man",
                    "man_2",
                    "man_3",
                    "man_4",
                    "nordic_walking",
                    "paragliding",
                    "personal_injury",
                    "person_2",
                    "person_3",
                    "person_4",
                    "person_add",
                    "person_add_alt",
                    "person_add_alt_1",
                    "person_off",
                    "person_outline",
                    "person_remove",
                    "person_remove_alt_1",
                    "psychology",
                    "psychology_alt",
                    "scuba_diving",
                    "self_improvement",
                    "skateboarding",
                    "sledding",
                    "snowboarding",
                    "snowshoeing",
                    "sports_gymnastics",
                    "sports_handball",
                    "sports_martial_arts",
                    "surfing",
                    "woman_2",
                    "adam",
                    "businessman3",
                    "businessman_add",
                    "businessman_delete",
                    "businessman_edit",
                    "businessman_find",
                    "businessman_preferences",
                    "businessman_view",
                    "dude",
                    "nurse2",
                    "patient",
                    "pilot2",
                    "pirate",
                    "policeman_german",
                    "policeman_usa",
                    "robber",
                    "security_agent_add",
                    "security_agent_delete",
                    "security_agent_edit",
                    "stockbroker3",
                    "superhero",
                    "surgeon2",
                    "user2",
                    "user3",
                    "user_add",
                    "user_back",
                    "user_delete",
                    "user_edit",
                    "user_find",
                    "user_information",
                    "user_into",
                    "user_lock",
                    "user_new",
                    "user_preferences",
                    "user_refresh",
                    "user_time",
                    "user_view"
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerIconResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 403,
                  "title": "missing-installers-read",
                  "code": "missing-installers-read"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 409,
                  "title": "installer-icon-conflict",
                  "code": "installer-icon-conflict"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 503,
                  "title": "installer-icon-unavailable",
                  "code": "installer-icon-unavailable"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/installers/export-count": {
      "get": {
        "tags": [
          "Installers"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetInstallerExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "includeActivationCode",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/installers": {
      "get": {
        "tags": [
          "Installers"
        ],
        "summary": "List installers with locations, tags, account state and last activity.",
        "description": "### Access and storage\r\n            \r\n- Requires an active manager, Installers1 (68), PermissionInstaller2 Read and a whole-tenant KID grant.\r\n- Bank/location-only grants and Write without Read are insufficient. Current account, credential stamp,\r\n  tab, permission and tenant scope are checked on every page through the bounded 60-second snapshot.\r\n- Reads only A{TenantId:D4}.Log7, BankId=TenantId and eUserId.Installeres through InstalleresLast (1–999).\r\n  Tenant comes exclusively from trusted site configuration. Passwords and activation secrets are never selected.\r\n            \r\n### Returned data\r\n            \r\n- Object identifiers are canonical KIDs. Derive the displayed UserId from the installer KID.\r\n- Locations and tags use the same JSON/legacy decoding as residents. State is retained, including NoAccess\r\n  and locked/deleted/history tags. These are metadata, never additional permissions for the caller.\r\n- Disabled installers remain visible. Deleted installers follow the caller's RetentionDays; malformed/future\r\n  deletion values are hidden. LastActiveAt is the Alive row's MS2000 converted to UTC, never its Text value.\r\n- Missing/invalid Enabled and activity are null; missing Deleted is zero. Reads do not update activity.\r\n- includeActivationCode=true additionally requires Installer Create and returns each visible installer's\r\n  FlexActivation.User() activationCode using this site's tenant bank. Default false omits the code.\r\n  This is sensitive activation data; do not log/cache/share it. No password is returned.\r\n            \r\n### Paging, filtering and ordering\r\n            \r\n- pageSize is 1–250 (default 50). Follow nextCursor until null; a page may be empty due to retention.\r\n- filter is a literal, case-insensitive Name/Email substring, at most 128 characters. Wildcards are escaped.\r\n- Sorts: identity, name, email, locations, tags, deleted, enabled, lastActive; direction asc or desc.\r\n- Sort applies before paging. Text is ordinal case-insensitive; location/tag lists compare sorted numeric\r\n  IDs and then states lexicographically, not their displayed text or count. Identity breaks ties in the same direction.\r\n- Null values sort first ascending, last descending. Deleted sorts by timestamp, Enabled by null/false/true.\r\n- Identity ascending uses bounded keyset reads. Other sorts use a tenant-local index, at most 999 identities,\r\n  cached for 60 seconds, then fresh page details with retention reapplied. No per-installer queries.\r\n- Cursors are bound to caller, tenant, filter, ordering (page size may change). Restart without a cursor when any changes.\r\n  Concurrent updates are not a frozen snapshot; a removed cursor anchor requires restarting.\r\n            \r\n### Errors and limits\r\n            \r\n- 400: invalid-page, invalid-filter, invalid-sort or invalid-cursor. 401: invalid/revoked session.\r\n- 403: missing-installers-tab, missing-installers-read, missing-installers-create (codes) or missing-tenant-access.\r\n- 503 installers-unavailable: database unavailable or the 12-second deadline elapsed; no partial sorted result.\r\n  Retry manually. All responses are no-store. No installer writes are provided by this operation.",
        "operationId": "GetInstallers",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "includeActivationCode",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerDirectoryResponse"
                },
                "example": {
                  "items": [
                    {
                      "kid": "A6Q32oA6b1h",
                      "name": "Example installer",
                      "iconKid": "angel",
                      "email": "installer@example.test",
                      "locations": [
                        {
                          "kid": "A6Q1EoA6b2l",
                          "state": "Access"
                        }
                      ],
                      "tags": [
                        {
                          "kid": "A6Q50oA6b4D2t",
                          "state": "Unlocked"
                        }
                      ],
                      "enabled": true,
                      "deleted": false,
                      "deletedAt": null,
                      "lastActiveAt": "2026-09-25T12:34:56.789+00:00"
                    }
                  ],
                  "nextCursor": null
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 403,
                  "title": "missing-installers-read",
                  "code": "missing-installers-read"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 503,
                  "title": "installers-unavailable",
                  "code": "installers-unavailable"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/installers/{installerKid}": {
      "get": {
        "tags": [
          "Installers"
        ],
        "summary": "Read one installer and the same Person icon catalog used for administrators.",
        "description": "Requires active manager, Installers1, Installer Read and whole-tenant access, exactly as GetInstallers.\r\nThe canonical KID must use this site's tenant, BankId=TenantId, installer type and the installer UserId range.\r\nReturns 404 installer-not-found for absent or retention-hidden records. Disabled installers remain visible.\r\nAvailableIcons contains every eIcon with eIconSubject.Person metadata. A safe current non-Person icon\r\nappears first for display only. CanEditIcon additionally requires independent Installer Write.\r\nRead IconRevision before SetInstallerIcon; metadata and edit hints never grant authorization.\r\nNo-store; 12-second deadline; 400 invalid-installer-kid, 401/403 as for the list, 503 installers-unavailable.",
        "operationId": "GetInstaller",
        "parameters": [
          {
            "name": "installerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerDetailsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerDetailsResponse"
                },
                "example": {
                  "installer": {
                    "kid": "A6Q32oA6b1h",
                    "name": "Example installer",
                    "iconKid": "angel",
                    "email": "installer@example.test",
                    "locations": [
                      {
                        "kid": "A6Q1EoA6b2l",
                        "state": "Access"
                      }
                    ],
                    "tags": [
                      {
                        "kid": "A6Q50oA6b4D2t",
                        "state": "Unlocked"
                      }
                    ],
                    "enabled": true,
                    "deleted": false,
                    "deletedAt": null,
                    "lastActiveAt": "2026-09-25T12:34:56.789+00:00"
                  },
                  "canEditIcon": true,
                  "iconRevision": "5CE7200DE215F47D73E8C782F447813306BD7DD66F0C468AD961D92D0C950FDE",
                  "availableIcons": [
                    "angel",
                    "astrologer",
                    "astronaut",
                    "athlete",
                    "baby",
                    "bicyclist",
                    "bookkeeper",
                    "boy",
                    "businessman",
                    "businessman2",
                    "businessperson",
                    "businessperson2",
                    "businessperson3",
                    "businesswoman",
                    "businesswoman2",
                    "caesar",
                    "clown",
                    "cook",
                    "criminal",
                    "delivery_man",
                    "delivery_man_parcel",
                    "devil",
                    "disability",
                    "doctor",
                    "dude1",
                    "dude2",
                    "dude3",
                    "dude4",
                    "dude5",
                    "dude6",
                    "engineer",
                    "face_scan",
                    "firefighter",
                    "genius",
                    "girl",
                    "graduate",
                    "guard",
                    "hipster",
                    "holmes",
                    "judge",
                    "lecture",
                    "magician",
                    "motorcyclist",
                    "nurse",
                    "pastor",
                    "person",
                    "pilot",
                    "policeman",
                    "policeman_bobby",
                    "pontifex",
                    "schoolboy",
                    "scientist",
                    "security_agent",
                    "senior_citizen",
                    "senior_citizen2",
                    "singer",
                    "soldier",
                    "spy",
                    "stockbroker",
                    "stockbroker2",
                    "surgeon",
                    "teacher",
                    "teacher_blackboard",
                    "terrorist",
                    "user",
                    "user_earth",
                    "user_glasses",
                    "user_headphones",
                    "user_headset",
                    "user_message",
                    "user_mobile_phone",
                    "user_monitor",
                    "user_smartphone",
                    "user_sunglasses",
                    "user_telephone",
                    "video_chat",
                    "video_chat2",
                    "woman",
                    "woman2",
                    "woman3",
                    "woman4",
                    "worker",
                    "worker2",
                    "user_mobilephone",
                    "accessibility",
                    "accessibility_new",
                    "accessible",
                    "accessible_forward",
                    "account_box",
                    "account_circle",
                    "assignment_ind",
                    "contact_page",
                    "face",
                    "face_unlock",
                    "manage_accounts",
                    "no_accounts",
                    "perm_contact_calendar",
                    "perm_identity",
                    "pregnant_woman",
                    "record_voice_over",
                    "rowing",
                    "settings_accessibility",
                    "transcribe",
                    "voice_over_off",
                    "contacts",
                    "contact_emergency",
                    "contact_mail",
                    "contact_phone",
                    "co_present",
                    "person_add_disabled",
                    "person_search",
                    "attribution",
                    "how_to_reg",
                    "remember_me",
                    "face_retouching_natural",
                    "face_retouching_off",
                    "portrait",
                    "badge",
                    "directions_run",
                    "directions_walk",
                    "person_pin",
                    "person_pin_circle",
                    "run_circle",
                    "streetview",
                    "transfer_within_a_station",
                    "support_agent",
                    "child_care",
                    "assist_walker",
                    "blind",
                    "downhill_skiing",
                    "elderly",
                    "elderly_woman",
                    "emoji_people",
                    "engineering",
                    "face_2",
                    "face_3",
                    "face_4",
                    "face_5",
                    "face_6",
                    "follow_the_signs",
                    "hiking",
                    "kayaking",
                    "kitesurfing",
                    "man",
                    "man_2",
                    "man_3",
                    "man_4",
                    "nordic_walking",
                    "paragliding",
                    "personal_injury",
                    "person_2",
                    "person_3",
                    "person_4",
                    "person_add",
                    "person_add_alt",
                    "person_add_alt_1",
                    "person_off",
                    "person_outline",
                    "person_remove",
                    "person_remove_alt_1",
                    "psychology",
                    "psychology_alt",
                    "scuba_diving",
                    "self_improvement",
                    "skateboarding",
                    "sledding",
                    "snowboarding",
                    "snowshoeing",
                    "sports_gymnastics",
                    "sports_handball",
                    "sports_martial_arts",
                    "surfing",
                    "woman_2",
                    "adam",
                    "businessman3",
                    "businessman_add",
                    "businessman_delete",
                    "businessman_edit",
                    "businessman_find",
                    "businessman_preferences",
                    "businessman_view",
                    "dude",
                    "nurse2",
                    "patient",
                    "pilot2",
                    "pirate",
                    "policeman_german",
                    "policeman_usa",
                    "robber",
                    "security_agent_add",
                    "security_agent_delete",
                    "security_agent_edit",
                    "stockbroker3",
                    "superhero",
                    "surgeon2",
                    "user2",
                    "user3",
                    "user_add",
                    "user_back",
                    "user_delete",
                    "user_edit",
                    "user_find",
                    "user_information",
                    "user_into",
                    "user_lock",
                    "user_new",
                    "user_preferences",
                    "user_refresh",
                    "user_time",
                    "user_view"
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallerDetailsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 403,
                  "title": "missing-installers-read",
                  "code": "missing-installers-read"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 503,
                  "title": "installers-unavailable",
                  "code": "installers-unavailable"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/diagnostics/live-logs": {
      "get": {
        "tags": [
          "LiveLogs"
        ],
        "summary": "Read recent live logs from Portal API, Equipment API and Portal Web.",
        "description": "Requires Logs1, Managers Read and a whole-tenant grant. Every read rechecks the bounded\r\nmanager snapshot before source/cache access. No tenant, server URL or arbitrary query is accepted.\r\nEach server retains at most 100 sanitized events for 15 minutes in memory; restart clears history.\r\nApplication Information and all Warning-or-higher events are captured. This is neither Logz.io history nor a durable audit trail.\r\nPoll no faster than refreshAfterSeconds (3). Server errors are independent: check each errorCode.\r\nlive-logs-not-configured means disabled/missing settings; live-logs-unavailable means a source failed\r\nor its tenant/role did not match. Empty successful cards mean no recent events on that instance.\r\nBankId/UserIds are requested, authorized diagnostic IDs, scoped by tenantKid; no balance values appear.\r\n401 revoked/invalid session; 403 missing-logs-tab, missing-managers-read or missing-tenant-access;\r\n503 live-logs-unavailable for unavailable authorization storage. Browser responses are no-store.\r\nMultiple replicas have separate buffers; this endpoint does not aggregate all replicas.",
        "operationId": "GetLiveLogs",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LiveLogsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiveLogsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiveLogsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/active-count": {
      "get": {
        "tags": [
          "Locations"
        ],
        "summary": "Count accessible active locations for the Locations1 navigation icon.",
        "description": "Requires an active manager, Locations1 (65), Bank Read, Location Read and current site/bank/location grants.\r\nCounts distinct Log24 locations (BankId at least 1000) with Enabled exactly 1 and Deleted zero;\r\nmissing Deleted means zero, missing/invalid Enabled or malformed Deleted are excluded.\r\nThese state rules also apply to all-bank managers. For limited grants the parent bank must remain\r\nvisible under RetentionDays. Optional bankKid narrows the count to one canonical bank KID in this tenant, intersecting current grants. No search or paging is accepted.\r\nReturns count and a ready-to-render iconKid containing Kid.Count. The aggregate is read afresh on each request; permission snapshots live at most 60 seconds.\r\n401: invalid/revoked session. 403: missing-banks-tab, missing-bank-read, missing-location-read or missing-resource-access.\r\n503 locations-unavailable: storage unavailable or the 12-second deadline elapsed; retry manually. No-store.",
        "operationId": "GetActiveLocationCount",
        "parameters": [
          {
            "name": "bankKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveLocationCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveLocationCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveLocationCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations": {
      "get": {
        "tags": [
          "Locations"
        ],
        "summary": "List accessible locations with parent banks, Visma customer numbers and authorized activation codes.",
        "description": "### Authorization and data\r\nRequires an active manager, Locations1 (65), Bank Read, Location Read and site/bank/location grants.\r\nEvery page rechecks the current bounded manager snapshot. Location-only grants never reveal sibling locations.\r\nReads only the site's Log24; BankId must be at least 1000. Discovery requires Name, Icon, VismaCustNo, Enabled or Deleted.\r\nAn explicit site-wide grant lists all states, including disabled locations and deletions outside RetentionDays.\r\nLimited grants require the location's Enabled value to be exactly 1 (missing/other values are hidden).\r\nFor limited grants, both bank and location deletion follow RetentionDays: zero or an inclusive window ending now;\r\nmissing Deleted means zero, malformed/future values are hidden. All filtering precedes paging.\r\nEnabled is true only for stored 1. Deleted is null when malformed, otherwise indicates a positive MS2000 value.\r\nDeletedAt is the corresponding UTC timestamp, or null for zero, invalid or unrepresentable values.\r\nBankKid and Kid are canonical identifiers. Missing names/VismaCustNo are empty, invalid icons use bank_building/house.\r\nHasAllBanksAccess indicates an explicit site-wide grant. Both activation codes require this grant;\r\nBankActivationCode additionally requires Bank Create and LocationActivationCode requires Location Create.\r\nOtherwise the code is null. A displayed code never grants API permission.\r\n            \r\n### Optional columns\r\nfields: comma-separated vismaCustNo, bankActivationCode, locationActivationCode, address, zip, longitude, latitude,\r\nteltonikaSms, alternativeBankName, mask, timeZone, online, lastContactAt.\r\nText filtering also searches all selected stored columns before pagination; unselected extra columns do not match.\r\nDecimal coordinates and gift amounts accept dot/comma; date searches accept ISO or dd.MM.yyyy/dd-MM-yyyy, UTC for contacts.\r\nbankName is an optional selection marker for showing the bank name and bank icon together after the location in the portal. Core bank identity properties remain populated.\r\nBilling fields (also accepted as sort keys): vismaCrAcNo, vismaInvoiceVersion, vismaOrdre, vismaPNTurnover, vismaPNSettlement, vismaSettlement, vismaVAT, vismaServiceKey, vismaStart, vismaNote, hiddenNote, vismaGuaranteeMonth, vismaGuaranteeUnder, vismaGuarantee, vismaGuaranteeCustomer, vismaGuaranteeOver, gift, giftBegin, giftEnd, giftSplit, giftPN, soapEnd.\r\nSoapEnd reads location-owned eSetting.SoapEnd (3025) as legacy date text, like vismaStart; it is not MS2000 and sorts as stored text.\r\nGiftPN uses legacy location setting 1620 (the shared enum calls this identity DurationIsETA for units).\r\nBilling fields return location-owned stored text; omitted fields are null, selected missing fields are empty.\r\nTeltonikaSms, alternativeBankName, mask and timeZone are location-owned TeltonikaSMS, Bank, Access and TimeZone settings, returned as stored text without inheritance.\r\nMissing selected text is empty; unselected text is null. Preserve mask syntax, phone prefixes and legacy time-zone codes (100 means UTC+1).\r\nOmitted/empty means core identifiers, status, names and icons only; unselected properties are null.\r\nAddress and Zip are location-owned settings without bank fallback. Coordinates are decimal degrees (stored microdegrees / 1,000,000), null when missing/invalid.\r\nOnly selected settings are joined, plus the sort setting and VismaCustNo when required for search. Codes retain all scope/Create checks.\r\nincludeCoordinates=true additionally returns latitude/longitude for map presentation without adding them to text search.\r\nDefaults to false; keep it unchanged across cursor requests. Authorization and coordinate null/degree rules are unchanged.\r\nThe response fields array names the requested columns. Keep fields unchanged across cursor requests; order and duplicates do not matter.\r\n            \r\nOnline and LastContactAt read the tenant-bound Alive table only when selected or sorted, for Log24-discovered visible main units (Alive.UnitId = Alive.MainId).\r\nOnline is false if any is offline, true only for a nonempty entirely known-online set, otherwise null.\r\nLastContactAt is the latest MS2000 in (0,now], returned as UTC ISO 8601; absent/invalid contacts are null.\r\nIt means last contact, not last machine run. Deleted units follow RetentionDays; orphan Alive rows do not contribute.\r\n            \r\n### Search, sorting and paging\r\nbankKid: optional canonical bank KID in this tenant; intersects current grants before filtering/paging.\r\nNever broadens access or changes all-bank privileges. Repeat it unchanged with cursors; invalid/wrong-tenant KIDs return 400 invalid-bank.\r\npageSize: 1–250, default 50. filter: at most 128 characters, literal case/accent-insensitive substring of bank name,\r\nlocation name or VismaCustNo. Exact canonical/readable/site-relative bank and location KIDs are supported.\r\nComplete bank/location activation codes match only when the caller could view that code; bank codes include tenant,\r\nlocation codes use the trusted site tenant. No cross-tenant reads. Empty filter lists all accessible locations.\r\nsort: name (default), bankName, vismaCustNo, address, zip, longitude, latitude, teltonikaSms,\r\nalternativeBankName, mask, timeZone, online, lastContactAt, bankActivationCode or locationActivationCode;\r\ndirection: asc (default) or desc. MySQL utf8mb4_general_ci\r\ntext ordering precedes LIMIT. Coordinates (validated microdegrees) and legacy timeZone sort numerically;\r\nOnline sorts unknown/offline/online; lastContactAt sorts chronologically; missing/invalid numeric values sort first ascending and last descending. Gift, giftBegin and giftEnd also sort numerically; other settings sort as text.\r\nCodes sort numerically using FlexActivation: stream authorized matching rows and retain at most pageSize+1 candidates.\r\nCode sorts may take longer on large result sets; narrow filter when needed. No full catalogue is retained in memory.\r\nSorting codes requires permission to see that code (otherwise 403 missing-code-access).\r\nNumeric bank/location identities break ties in the same direction for every sort.\r\nFollow nextCursor until null; cursors are protected, expire after 15 minutes and are bound to tenant, manager,\r\nresource grants, retention, filter, enabledOnly, sort, direction (page size may change). Restart without a cursor when these change.\r\nenabledOnly: false by default. When true, exclude locations whose Enabled is not exactly 1 before paging.\r\nThis narrows the authorized view only; deletion/retention rules and activation-code permissions remain unchanged.\r\nConcurrent edits are not a frozen snapshot; renamed rows may move. No count or full catalogue is returned.\r\n            \r\n### Errors\r\n400: invalid-bank, invalid-page, invalid-filter, invalid-sort, invalid-fields, invalid-cursor. 401: invalid/revoked session.\r\n403: missing-banks-tab, missing-bank-read, missing-location-read, missing-resource-access, missing-code-access.\r\n503 locations-unavailable: storage unavailable or the 12-second deadline elapsed. Retry manually. No-store.",
        "operationId": "GetLocations",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeCoordinates",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "bankKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationDirectoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/count": {
      "get": {
        "tags": [
          "Locations"
        ],
        "summary": "Count every location matching the same filters, selected search columns and permissions as GetLocations.",
        "description": "Requires Locations1, Bank Read, Location Read and current tenant-bound resource grants. Uses the identical Log24 discovery, scope, retention, Enabled, KID/code search and selected-field filtering as GetLocations. No cursor or page limit applies. Count is exact at query time, not an immutable snapshot of subsequent pages; concurrent data or permission changes may change a later export. sort/direction retain the listing's validation and code-access checks. No-store. 400 invalid filters/fields/scope; 401 invalid session; 403 missing permissions; 503 locations-unavailable or 12-second deadline. Retry manually.",
        "operationId": "GetLocationCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bankKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/locations": {
      "get": {
        "tags": [
          "LocationSearch"
        ],
        "summary": "Search location Name, Bank (alternative bank name), Zip, Address, VismaCustNo and TeltonikaSMS in Log24.",
        "description": "### Access and identifiers\r\n            \r\n- Requires a current **Tab**, **Location Read**, site-bound resource grants and **RetentionDays** visibility.\r\n- Only **BankId ≥ 1000** is searchable.\r\n- Accepts exact canonical or readable KIDs. An omitted tenant comes from trusted site configuration; `matchedSetting` is `Kid`.\r\n- Cross-tenant or inaccessible identities return no results.\r\n            \r\n### Text search\r\n            \r\n- Searches **Name**, **Bank** (alternative bank name), **Zip**, **Address**, **VismaCustNo** and **TeltonikaSMS** in Log24.\r\n- Literal, case-insensitive substring matching; **2–128 trimmed characters**.\r\n- Returns `matchedSetting` and `matchedValue`; Name has first priority.\r\n- A separate **60-second cache** coalesces requests.\r\n            \r\n### Results and parent banks\r\n            \r\n- At most **50 matching locations**. `hasMore` counts locations.\r\n- When Bank Read is granted, includes distinct parent banks with `isContext=true`.\r\n- Parent bank context contains only name/icon, never contact fields.\r\n- **Merge all items by KID.**",
        "operationId": "SearchLocations",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/location-activation": {
      "get": {
        "tags": [
          "LocationSearch"
        ],
        "summary": "Decode a location activation code and resolve its visible name and icon in Log24.",
        "description": "### Access and lookup\r\n            \r\n- Uses the same authorization as `SearchLocations`.\r\n- Codes contain bank/location, not tenant; the **trusted site supplies the tenant**.\r\n- Invalid, missing or inaccessible locations return no items. No other tenant is queried.\r\n- Resolves the visible name and icon in **Log24**.\r\n            \r\n### Shared activation-code rate limit\r\n            \r\n- The bank, location and resident code endpoints share **5 calls per 10 minutes** and **20 per hour**, per manager.\r\n- Invalid calls count toward the quota.\r\n- **HTTP 429** includes `Retry-After`; wait before trying again.",
        "operationId": "SearchLocationActivation",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/booking-calendars": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read dated reservation calendars with location opening hours already applied.",
        "description": "Requires an active manager, Bookings1, Location Read, Unit Read and matching site/bank/location\r\nscope and RetentionDays visibility. Authorization precedes all settings reads. No User Read required.\r\nFrom is an optional local yyyy-MM-dd date, default today in the location time zone; days is 1–31, default 14.\r\nThe API expands BookCalendar v3 and applies the same opening plan as GetLocationOpeningHours,\r\nincluding controller inheritance, overnight spill, holidays and custom date exceptions.\r\nDays carry concrete dates and weekday 0=Sunday. Slots use local startMinute and durationMinutes,\r\nclipped to 0–1440 within each date. Type 0=reservation period, 1=chance, 2=closed, 3=unknown opening hours.\r\nMissing/hidden/cyclic opening owners remain unknown, never unrestricted. Invalid date exceptions are ignored individually.\r\nThe no-calendar sentinel is omitted;\r\nmalformed calendars are omitted. Configured calendars may have empty open days.\r\nGrouping preserves stored calendar identity and also separates different effective dated schedules.\r\nThese are wall-clock schedules, not UTC reservations, occupancy or a guarantee of bookability.\r\nTwo bounded Log24 reads share an eight-second deadline; only the authorized units may own schedules.\r\nNo writes. 400 invalid KID/range, 401 inactive session, 403 denied, 404 hidden location, 503 unavailable data.\r\nDo not interpret 503 or unknown as closed or unrestricted. Refresh on navigation.",
        "operationId": "GetLocationBookingCalendars",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 14
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationBookingCalendarsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationBookingCalendarsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationBookingCalendarsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/booking-rules": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read localized configured reservation rules for the location's visible units.",
        "description": "Requires an active manager, an assigned Tab, Location Read, Unit Read, matching site/KID scope and\r\nRetentionDays visibility, identical to GetLocationUnits. Authorization precedes the bounded Log24 read.\r\nThe trusted site selects the tenant. Only visible units may contribute settings or dependency names.\r\nUnits are grouped by their full calendar AND rule settings. Different policies in one calendar receive\r\nSettingsConflict; presentation groups do not create separate quotas. This is configuration, not a\r\nresident-specific permission, real-time availability check or booking validation.\r\n            \r\nResponse: locationKid, calculatedAt (UTC), groups [{name?, units [{kid,name}], rules [{code,text,warning,parts}]}].\r\nGroups provide the compact API presentation: identical visible rules are combined;\r\nshared rules appear once with common=true and localized name/help, followed by differing rules per unit group.\r\nEach group includes units and rules. Reservation quota scopes remain separate.\r\nEach optional parts array contains ordered {text,isValue} objects. Concatenating their text without separators\r\nreproduces the unchanged rule text. isValue identifies values that clients may emphasize. If parts is absent\r\nor empty, use rule.text. All text is plain text, never HTML; markup-like stored values must be escaped by clients.\r\nAccept-Language localizes names and text, including value placement; codes remain stable.\r\nCurrency comes from registered settings, never the UI language; unknown currency is explicit.\r\nV3 calendars are supported; malformed calendars return InvalidCalendar. Missing calendars are omitted,\r\nexcept instant reservation. Missing legacy settings use their legacy defaults; malformed values produce\r\nUnknownSettings. A zero week limit describes the legacy 400-day horizon; positive limits include this week.\r\nBefore/after/add-time default to 15 minutes; drying-room search defaults to 4320 minutes.\r\nNo user bookings are loaded and no reservation or maintenance action is performed.\r\n            \r\nAt most 255 units / 8192 values, eight seconds total and two concurrent settings reads. No Alive reads\r\nfor rule data. 400 invalid KID/site; 401 expired/inactive session; 403 missing scope/tab/read permission;\r\n404 missing/retention-hidden location; 503 busy/unavailable/invalid/oversized storage. Never treat 503 as\r\nunrestricted booking. Empty groups means no visible configured booking calendar.",
        "operationId": "GetLocationBookingRules",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationBookingRulesResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationBookingRulesResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationBookingRulesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/controllers/{controllerKid}": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read an authorized controller using its canonical Controller KID with MainId.",
        "description": "Same authorization, tenant, scope and retention checks as GetUnitOverview. The authorized Alive hierarchy must identify this unit as its own controller. Controller data shares the main unit's Log24 storage. Core is the temporary settings and states selection; unavailable type metadata never invents fields.",
        "operationId": "GetControllerOverview",
        "parameters": [
          {
            "name": "controllerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDetailsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDetailsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDetailsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/controllers/{controllerKid}/groups/{kind}/{group}": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read the controller's temporary Core settings or states from its main unit.",
        "description": "Rechecks GetControllerOverview authorization and hierarchy. Uses only fields declared for the main unit type; missing Core metadata returns an empty items array without a storage read. Existing unit setting operations retain their authorization and revisions.",
        "operationId": "GetControllerGroup",
        "parameters": [
          {
            "name": "controllerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitGroupResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitGroupResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitGroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/units": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Get the location label and its units, ordered by unit number.",
        "description": "### Access and visibility\r\n            \r\n- Requires an active manager, at least one assigned **Tab**, **Location Read**, **Unit Read** and matching tenant/bank/location access.\r\n- Send a canonical location KID on this site.\r\n- Location and unit deletion both follow **RetentionDays**; missing Deleted means zero.\r\n- Current unit settings, Cycle, Enabled, OutOfOrder, WashDocId, Connected, Started and Done come from **Log24**, in one bounded query.\r\n            \r\n### Names, icons and cycle\r\n            \r\n- Missing or invalid unit icons use `object_cube`; explicitly configured icons are preserved.\r\n- The API adds the unit number to `iconKid.Text`. The `g/object_cube` asset prints it on the box face.\r\n- Unit names resolve `[eLocalization numeric ID]` placeholders using `Accept-Language` on each request, defaulting to `en-GB`. Unknown IDs remain unchanged.\r\n- Cycle uses the newest MS2000 from `eSetting.Cycle` or `eState.Cycle`; state wins ties.\r\n- Absent or invalid cycle values return null. `cycle` is an enum name; `cycleText` is its localized label.\r\n- `unitType` is the effective numeric type; `unitTypeName` is the eUnitType name when defined; `unitTypeSource` identifies the source setting.\r\n- Only the original packed UnitType determines the type, using the eight-bit `(value >> 1) & 255` rule. UnitType2 is never an override or fallback.\r\n- Missing/invalid types return null, never an invented Type000. Unknown numeric types are retained without claiming metadata support.\r\n- `progress` contains `status`, nullable `percent`/`remainingSeconds` and `calculatedAtUtc`. The API recalculates from Started/Done at request time; clients need no MS2000 or KID calculations.\r\n- `Estimated` uses floor(clamp((now-Started)/(Done-Started)*100,0,100)), including 100 at/after the expected end. Remaining seconds are clamped at zero.\r\n- `UnknownEndTime` covers missing/nonpositive/invalid times and Done not after Started; percent and remainingSeconds are null.\r\n- Only Started/Done JSON Text timestamps affect progress. Cycle, Enabled, OutOfOrder, Connected and sequence IDs do not. No user identities are read for progress.\r\n- `terminal` is an optional `{kid,name,iconKid}` with a canonical Controller KID (MainId, UnitId=0), resolved from the trusted tenant's Alive.MainId for the exact visible unit set. The parent must be a visible Log24 unit in this location; an existing parent Alive row must map UnitId to itself. A missing parent Alive row is allowed when a visible child's MainId explicitly identifies it.\r\n- Missing, invalid, hidden, chained or unavailable hierarchy returns terminal=null; never guess a self-parent. Terminal names use the main unit’s eState.ComputerName, matching GetTerminals without falling back to eSetting.Name and its iconKid includes the main unit number. Offline is independent.\r\n            \r\n### Results and cache\r\n            \r\n- At most **255 units**, ordered by unit number. No paging or count query.\r\n- No visible units returns empty items.\r\n- Unit data is cached for up to **10 seconds** and location labels for up to **60 seconds**. Authorization is reapplied on every call.\r\n            \r\n### Errors\r\n            \r\n- **HTTP 404:** missing or invisible location.\r\n- After tab/resource checks, **HTTP 403** may include `reason` of `missing-location-read` or `missing-unit-read`. No business storage is read on denial.",
        "operationId": "GetLocationUnits",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationUnitsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationUnitsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationUnitsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/{unitKid}": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read an authorized unit and its type's setting/state groups.",
        "description": "### Access\r\n- Requires an active manager, at least one assigned Tab, Location Read, Unit Read and a matching tenant/bank/location grant.\r\n- Send a canonical unit KID on this site. The unit and its parent location must be visible within RetentionDays.\r\n- Uses the same bounded, ten-second location snapshot as GetLocationUnits. Authorization is reapplied on every call, before metadata is exposed.\r\n### Result\r\n- Returns `location`, `unit`, `descriptorAvailable`, `settingGroups` and `stateGroups`.\r\n- Group identifiers are stable eSettingGroup/eStateGroup names, deduplicated and ordered by numeric enum value.\r\n- Metadata comes from SettingsAndStates.json and the shared enums, selected by the unit's effective type; no hardware connection is made.\r\n- Missing, malformed or unsupported types return descriptorAvailable=false and empty groups. No default type is substituted.\r\n- This read-only operation returns group metadata, not setting/state values or editing rights.\r\n### Errors\r\n- 400: invalid/foreign unit KID. 401: sign in again. 403: missing tab/scope/read access. 404: missing or retention-hidden location/unit. 503: storage unavailable.\r\n- Accept-Language localizes names/cycle labels; group identifiers remain language independent.",
        "operationId": "GetUnitOverview",
        "parameters": [
          {
            "name": "unitKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDetailsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDetailsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDetailsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/{unitKid}/groups/{kind}/{group}": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read the declared settings or states in one authorized unit group.",
        "description": "### Access\r\n- Same active manager, Tab, location grant, Location Read, Unit Read and RetentionDays checks as GetUnitOverview.\r\n- `kind` is settings or states. `group` is an exact identifier returned by GetUnitOverview. The server selects fields from the effective unit type, never from client-supplied setting IDs.\r\n### Values and limits\r\n- Bounded Log24 reads for declared current-unit fields; newest MS2000 per field, no default substitution. Settings join the exact bank Log2 record for `sync` (only 1 means acknowledged) and batch current Log7 editor names/icons into `changedBy`. Missing sync is null, never success.\r\n- `changedBy` is null when no editor is recorded (UserId zero); display no user icon or name in that case. Unknown nonzero editors retain their display identity even without a KID.\r\n- `canReadHistory` identifies fields supported by GetUnitSettingHistory. Fetch history only on demand. Sync-only changes and editor label changes do not invalidate the value revision or change MS2000.\r\n- `hasHistory` indicates that the setting has at least one bank Log2 history record. Show history controls only when both canReadHistory and hasHistory are true.\r\n- Settings include `canEdit`, per-field `revision` and input constraints. Use SetUnitSetting to save; Unit Write is required. States are always read-only. Dynamic-option and other-scope editors are not supported.\r\n- Optional `valueFormat` selects a display/editor; Price comes from AttributeMetaRegEx(RegExs.Price). Display raw value/100 with two decimals, convert back exactly before saving. `pattern` is a .NET regex on raw storage text, never display text. Minimum/maximum also use raw units. Null/unknown formats use ordinary presentation. Empty optional values stay empty.\r\n- `valueStatus` is stored, missing, other-scope or redacted. A stored null/empty value remains stored. MainUnit/other-object bindings have no value; this endpoint does not infer their owning KID or borrow the current unit's value.\r\n- Hidden settings are omitted; credential settings are redacted and never read. Enum field/group names are stable identifiers.\r\n- At most 512 stored fields and 16,384 characters per value; ambiguous or oversized data fails with 503, never partial results. Values are uncached; type/location snapshots retain their normal 10/60-second limits. Poll settings at most every five seconds and states every ten seconds, pausing hidden pages and never overlapping requests.\r\n### Errors\r\n- 400: invalid kind, group syntax or unit KID/site. 401: sign in again. 403: missing tab/scope/read permission. 404: missing/retention-hidden unit/location or group not declared for this type. 503: storage unavailable or invalid bounded response.",
        "operationId": "GetUnitGroup",
        "parameters": [
          {
            "name": "unitKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitGroupResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitGroupResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitGroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/{unitKid}/groups/settings/{group}/{setting}/history": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read a bounded page of changes to one declared unit setting.",
        "description": "### Access and scope\r\n- Same manager, assigned Tab, location grant, Location Read, Unit Read and RetentionDays checks as GetUnitGroup.\r\n- The group and exact setting identifier must be declared for this unit type and bound to the current unit. Hidden/credential/other-scope fields are not exposed.\r\n- Audit access exposes only editor KID, kind, current display name and icon; it grants no access to their account or directory. Manager/service labels use bank zero; installer labels use the site's tenant bank; resident labels use this unit's bank.\r\n### Paging and values\r\n- Newest first from bank Log2, with stored value, source MS2000, Sync and editor. Names/icons are current Log7 labels, not historical snapshots. Unknown editors have a null KID and may have an empty name.\r\n- Page `valueFormat` matches GetUnitGroup. Price displays value/100; history values remain raw. Restore by submitting the unchanged raw value and the current field revision, without a second multiplication.\r\n- `changedBy` is null for UserId zero; display no user icon or name in that case.\r\n- `limit` is 1–50 (default 25). Pass `nextBeforeMs2000` as `beforeMs2000` for the next page. Null means no more rows. No count query, defaults or cache.\r\n- Sync is the flag on that exact Log2 record: only 1 means acknowledged. Null means no known flag, never success. A sync-only update does not change the value revision or modification timestamp.\r\n- Fetch history on demand, not once per visible row. At most 16,384 characters per value; oversized/ambiguous data fails the whole page.\r\n### Errors\r\n- 400 invalid input/site; 401 login required; 403 missing access; 404 hidden unit/location or unsupported field/group; 503 storage failure. All storage work has an eight-second deadline.",
        "operationId": "GetUnitSettingHistory",
        "parameters": [
          {
            "name": "unitKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "setting",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "beforeMs2000",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitSettingHistoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitSettingHistoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitSettingHistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/icons": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Resolve up to 32 visible unit icons, adding the online/offline under-icon on demand.",
        "description": "Repeat the kid query parameter with canonical unit KIDs from this site. Requires the same active\r\nmanager, assigned Tab, location scope, Location Read, Unit Read and RetentionDays visibility as GetLocationUnits.\r\nOnly after authorization, reads this site's Alive rows by exact bank/location (cached up to 10 seconds).\r\nOffline=1 sets Kid.Icons[1] to eIcon.close; Offline=0 sets it to eIcon.check.\r\nMissing rows, null and other Offline values retain the configured icon without a status decoration.\r\nUnitId text, primary icon and other presentation fields are preserved. Never infers offline from Cycle or MainId.\r\nReturns items with kid, opaque iconKid, nullable offline (null for missing/unknown Alive), and status.\r\nPer-item 403/404/503 has null iconKid/ offline; never interpret a failed lookup as online.\r\nInvalid/foreign/bulk input returns 400, expired sessions 401. Response is no-store. No writes.\r\nFetch only displayed icons, batch duplicate KIDs, poll at most every 10 seconds and pause hidden pages.\r\nUse iconKid unchanged with GetIconFromSet. The public image endpoint itself never looks up Alive.",
        "operationId": "GetUnitIcons",
        "parameters": [
          {
            "name": "kid",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitIconsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitIconsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitIconsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/icons": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Resolve up to 32 visible location icons with their units' combined online/offline status.",
        "description": "Repeat kid with canonical location KIDs from this site. Requires the same active manager, assigned\r\nTab, location scope, Location Read, Unit Read and RetentionDays visibility as GetLocationUnits.\r\nOnly the units returned by that authorized overview contribute; hidden units and orphan Alive rows do not.\r\nAny included unit with Alive.Offline=1 sets offline=true and Kid.Icons[1]=eIcon.close.\r\nA nonempty set whose every unit has Alive.Offline=0 sets offline=false and Kid.Icons[1]=eIcon.check.\r\nOtherwise offline=null: empty locations or incomplete/unknown Alive data do not claim to be online.\r\nMissing status never overrides a confirmed offline unit. Primary icon, LocationId text and other fields stay intact.\r\nItems contain kid, opaque iconKid, nullable offline and status. Per-item 403/404/503 returns no icon/status.\r\nInvalid/foreign/oversized input returns 400, expired sessions 401. A failed lookup never means online.\r\nRead only visible icons, batch/deduplicate and refresh at most every 10 seconds; pause hidden pages.\r\nAlive reads share the bounded ten-second cache with GetUnitIcons. HTTP is no-store. No writes.\r\nUse iconKid unchanged with GetIconFromSet; the anonymous image endpoint never queries Alive.",
        "operationId": "GetLocationIcons",
        "parameters": [
          {
            "name": "kid",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationIconsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationIconsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationIconsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/opening-hours": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read grouped opening hours, upcoming exceptions and the current opening status for a location.",
        "description": "Requires the same active manager, assigned Tab, Location Read, Unit Read, site/KID scope and RetentionDays\r\nvisibility as GetLocationUnits. Authorization precedes the opening-hours read. Only visible units can own or\r\ninherit schedules. The tenant is selected by site configuration, never by the caller.\r\n            \r\nOne bounded Log24 read, at most 255 units / 32,768 values, an eight-second deadline and two concurrent reads.\r\nOwner identity comes from the authorized same-location Alive.MainId hierarchy; opening settings remain in Log24.\r\nMissing/hidden/cyclic owners yield Unknown,\r\nnever assumed 24/7. Invalid date exceptions are ignored individually, preserving weekly hours and other valid exceptions.\r\nA known controller with no weekly limits is AllDay. Open/close fields inherit independently\r\nbackwards through the main terminal's week; child-unit hours and exceptions do not override that owner.\r\nEqual explicit times are Closed; short openings are preserved. Overnight intervals are supported.\r\n            \r\nWeekly rows use ISO weekdays 1–7. Exceptions are concrete local dates from today through two calendar months,\r\nincluding year boundaries. First Wednesday, configured holidays (including the legacy Great Prayer Day), then\r\nCustom3/Custom2/Custom1 take precedence. Custom1 wins duplicate dates; Feb 29 applies only in leap years.\r\nAn explicit date exception replaces overnight spill from the previous day.\r\n            \r\nStatus values: Open, Closed, AllDay, Unknown. Times are HH:mm with closesNextDay. isOpenNow is nullable;\r\nnextChange carries a UTC offset and is null for unknown/no transition within the next 369 days. This describes\r\nthe schedule only, not equipment readiness, permissions or a guarantee that the premises are accessible.\r\nLocation TimeZoneId/legacy TimeZone precede bank values; missing zones default to Europe/Copenhagen. Invalid\r\nzones return 503. DST gaps advance to the first valid minute; repeated times use first opening/last closing.\r\nNames and day labels use Accept-Language. calculatedAt identifies the observation; refresh on page navigation.\r\n            \r\n400 invalid KID/site; 401 expired/inactive session; 403 missing scope/tab/read permissions;\r\n404 missing/retention-hidden location; 503 unavailable, invalid or oversized storage. Do not show 503 as closed.",
        "operationId": "GetLocationOpeningHours",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationOpeningHoursResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationOpeningHoursResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationOpeningHoursResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/reservation-history": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read bank Log5 reservation history for the location's authorized visible units.",
        "description": "Requires Bookings1, Location/Unit Read, resource scope and RetentionDays visibility.\r\n            From is a local date from 2001, days 1–31. Returns every overlapping dated reservation revision,\r\n            including cancellations (positive absolute duration, cancelled=true), plus resident number and name. User Read is required.\r\n            Revision is UTC milliseconds since 2000-01-01. Weekly, AUT and isy events are excluded.\r\n            Events matching the current active snapshot by MS2000, LocationId, UnitId and UserId in the same bank are omitted.\r\n            At most 5000 events; overflow/storage failure returns 503, never truncated history. No writes.\r\n            Load only the visible calendar range; missing or failed history is not an empty history.",
        "operationId": "GetLocationReservationHistory",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationReservationHistoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationReservationHistoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationReservationHistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/reservations": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Read active tenant Log5 reservations for the location's authorized visible units.",
        "description": "Requires Bookings1, Location/Unit Read, a current manager session and resource/RetentionDays visibility.\r\n            Resident number and name require User Read in addition to Location/Unit Read. From is a local date (2001 or later), days 1–31.\r\n            StartMinute is local wall-clock minutes since 2000-01-01; weekly positions below 10080 are omitted\r\n            because they do not identify a concrete date. DurationMinutes is independent of calendar slots. Dated entries include every\r\n            overlap with the requested range. Cancelled, AUT and isy rows are excluded. Tenant Log5 is a current snapshot;\r\n            no bank-history fallback. At most 5000 entries; overflow returns 503, never partial occupancy. No writes.\r\n            Missing data must not be interpreted as availability. Refresh on date navigation.",
        "operationId": "GetLocationReservations",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationReservationsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationReservationsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationReservationsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/weather": {
      "get": {
        "tags": [
          "LocationWeather"
        ],
        "summary": "Get current weather for the authorized location's stored position or address.",
        "description": "Requires an active manager bearer session, assigned Tab, Bank Read, Location Read, matching resource scope\r\nand RetentionDays visibility. Location and parent bank must also satisfy GetObjectAddress visibility.\r\nAuthorization and a bounded Log-only address read precede every cache lookup. No Unit Read or Write is needed.\r\nUses eSetting.Latitude and Longitude (integer millionths of degrees) when both are valid; otherwise geocodes\r\navailable Address and Zip using the site's configured geocoder. Address-only/postal results are approximate.\r\nNever inherits another object's address, substitutes zero, writes settings or accepts caller-supplied coordinates.\r\nReturns status Available, LocationUnknown (no resolvable position), or Unavailable (provider/configuration failure).\r\ncurrent is null unless Available. Optional measurements are null when unknown. positionSource is Coordinates,\r\nAddress, or null. Times are UTC; temperature is Celsius, wind m/s, precipitation mm and humidity percent.\r\nOpen-Meteo model data, not an on-site sensor. Display attribution: Weather data by Open-Meteo, CC BY 4.0.\r\nCache: ten minutes per tenant/location/address revision; failures one minute. No-store HTTP. Refresh on navigation.\r\nFour concurrent provider lookups per process, twelve-second request deadline, no retries.\r\n400 invalid/foreign KID; 401 invalid/inactive manager; 403 scope/tab/read denial; 404 hidden/missing object;\r\n503 location-weather-unavailable on storage failure/deadline. Unavailable never means zero weather.",
        "operationId": "GetLocationWeather",
        "parameters": [
          {
            "name": "locationKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/LocationWeatherResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationWeatherResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationWeatherResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers": {
      "post": {
        "tags": [
          "ManagerCreation"
        ],
        "summary": "Create an empty enabled administrator with a previously unused manager identity.",
        "description": "Requires Managers1, independent Managers Read and Create, and whole-tenant scope.\r\nNo request body or client-selected tenant/UserId. Rechecks the actor account, credential stamp\r\nand access before allocation and again inside the write transaction, holding account and access locks through commit.\r\nNo password, email, tabs or scopes are assigned;\r\nno invitation is sent. Use GetManager and the existing editing operations after creation;\r\nprofile edits additionally require Managers Write.\r\nFinds the next unused manager identity and appends Enabled=1 and Icon=businessperson atomically. No Deleted setting is written.\r\nNo random marker, intentional delay or reservation verification. 15-second deadline.\r\nA tenant-specific MySQL advisory lock serializes allocation through commit (up to 5 seconds to acquire).\r\nAll creators must use the same lock on the same writer, including AMS and FRA. No table lock or schema change.\r\nIndependent writers will use modulo allocation by ServerId with a fixed common modulus (ADR 0015; not implemented).\r\nCreation is not idempotent; lock/storage failures return 503.\r\n401: login required. 403: missing-managers-tab/read/create or missing-tenant-access.\r\n409 manager-ids-exhausted: identity range exhausted.\r\n503 manager-creation-unavailable: outcome may be uncertain; inspect the directory before manual retry.\r\nNever automatically retry a timeout or lost response.",
        "operationId": "CreateManager",
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerCreationResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerCreationResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerCreationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "Managers"
        ],
        "summary": "List administrators in the site's eUserId.Managers through ManagersLast range.",
        "description": "### Access\r\n            \r\n- Requires an active manager session, **Managers1 (28)**, **PermissionManagers2 Read** and an explicit **tenant-wide KID grant**.\r\n- Bank/location-only grants are insufficient. Write does not imply Read; missing permission values default to Read.\r\n- Every request checks the current bounded session snapshot, at most **60 seconds** old.\r\n            \r\n### Returned metadata\r\n            \r\n- Reads `Log7`, bank zero, without reading credentials for listed managers. Disabled managers remain listed.\r\n- Deleted records follow the **caller's RetentionDays**.\r\n- Resource grants contain only this site's valid scopes. Tab grants are metadata, not proof of effective access.\r\n- `operationPermissions` and `retentionDays` describe the **listed manager**, never the caller.\r\n- **Service** comes from `PermissionService2` (3017) and has independent flags; it does not grant login or other categories' permissions.\r\n- The seven permission categories include **Installer** from `PermissionInstaller2`. GetInstallers requires Installer Read, Installers1 and tenant-wide access; GetInstaller uses the same read access and SetInstallerIcon additionally requires Installer Write; its flags do not authorize other resource categories.\r\n- Missing `Permission*2` settings default to Read; malformed settings grant nothing. Missing `RetentionDays` defaults to 10 days; invalid or negative values become zero. Explicit zero is preserved.\r\n- `isCurrentManager` identifies your own record. `canEditPermissions` requires Managers Write; on your own record it additionally requires that no other active manager has a whole-tenant KID grant. Use `SetManagerPermission` to save.\r\n            \r\n### Filtering and paging\r\n            \r\n- `filter` matches a case-insensitive substring of decoded **Name OR Email** before pagination. SQL wildcard characters are literal.\r\n- Pagination scans at most `pageSize` candidates. A page can be short or empty while `nextCursor` is non-null; **continue until null**.\r\n- Changing filter, sort or direction requires restarting **without a cursor**.\r\n- Concurrent inserts and changes are not a frozen snapshot.\r\n            \r\n### Ordering\r\n            \r\n- Selectable ordering uses a shared **seven-setting index**, cached for at most **60 seconds**, then reads fresh page details.\r\n- `lastActiveAt` is the current Alive krumb's MS2000 converted to UTC, not its Text value. Missing/invalid times are null and sort first ascending, last descending. Reads do not update activity.\r\n- Identity ascending retains its bounded database scan. All modes reapply authorization and deletion retention per page.\r\n- Text ordering is ordinal and case-insensitive. Kids compare sorted, site-relative numeric bank/location scopes; empty lists come first.\r\n- Enabled orders **missing, false, true**. Deleted orders by deletion time, zero first. Descending reverses ties as well.\r\n            \r\n### Limits and errors\r\n            \r\n- At most **20,000 matching identities** in the index. Larger selections return **HTTP 503** with `manager-directory-too-large`; narrow the filter.\r\n- A missing continuation identity after index refresh returns **HTTP 400**, `invalid-cursor`; restart without a cursor.\r\n- A cold index plus detail read has a **12-second deadline**. Data failure returns **HTTP 503**, never a silently truncated sorted list.",
        "operationId": "GetManagers",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "description": "Candidate batch size, 1–250, default 50. May change while following a cursor.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque continuation returned by the previous request, scoped to this site and caller.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "Optional name/email substring, at most 128 characters, trimmed. Empty lists all permitted managers.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "identity (default), name, email, organisation, kids, deleted, enabled or lastActive. Applied before pagination.",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "description": "asc (default) or desc. Identity breaks ties in the same direction.",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerDirectoryResponse"
                },
                "example": {
                  "items": [
                    {
                      "kid": "A6Q46o3B9ACA01h",
                      "name": "Example administrator",
                      "iconKid": "user",
                      "email": "admin@example.test",
                      "organisation": "Example organisation",
                      "enabled": true,
                      "deleted": false,
                      "deletedAt": null,
                      "lastActiveAt": "2026-09-25T12:34:56.789+00:00",
                      "retentionDays": 30,
                      "canEditPermissions": true,
                      "canEditTabs": true,
                      "isCurrentManager": false,
                      "canEditProfile": true,
                      "profileRevision": "61461452DAE1676B1E2EA99320D987DF7FB1AB26219A5A0CD3C748F944013A51",
                      "tabsRevision": "B8FB8869A5281D0DAD8A15E82DB9A7E6F1C6C89611DB79A276E557F7A6BDEA3E",
                      "operationPermissions": [
                        {
                          "resource": "Managers",
                          "level": "Read",
                          "canRead": true,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 1,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "Bank",
                          "level": "3",
                          "canRead": true,
                          "canWrite": true,
                          "canCreate": false,
                          "flags": 3,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "Location",
                          "level": "Read",
                          "canRead": true,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 1,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "Unit",
                          "level": "None",
                          "canRead": false,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 0,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "User",
                          "level": "48",
                          "canRead": false,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 48,
                          "canDelete": false,
                          "canRenameExternalId": true,
                          "canRename": true
                        },
                        {
                          "resource": "Installer",
                          "level": "5",
                          "canRead": true,
                          "canWrite": false,
                          "canCreate": true,
                          "flags": 5,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "Service",
                          "level": "Read",
                          "canRead": true,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 1,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "Tabs",
                          "level": "Read",
                          "canRead": true,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 1,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        },
                        {
                          "resource": "Kids",
                          "level": "Read",
                          "canRead": true,
                          "canWrite": false,
                          "canCreate": false,
                          "flags": 1,
                          "canDelete": false,
                          "canRenameExternalId": false,
                          "canRename": false
                        }
                      ],
                      "resourceGrants": [
                        {
                          "kid": "A6Q14o7D0b",
                          "scope": "Bank"
                        }
                      ],
                      "tabs": [
                        {
                          "id": 28,
                          "name": "Managers1",
                          "iconKid": ""
                        }
                      ]
                    }
                  ],
                  "nextCursor": null
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 403,
                  "title": "missing-tenant-access",
                  "code": "missing-tenant-access"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/{managerKid}/invitation": {
      "post": {
        "tags": [
          "ManagerInvitations"
        ],
        "summary": "Send an invitation allowing an existing manager to choose a password.",
        "description": "### Access and target\r\n- Requires an active manager, Managers1 (28), Managers Read and Write and tenant-wide access.\r\n- The same own-profile lock and sole active tenant-wide manager exception apply as for profile editing.\r\n- Current actor credentials/permissions and target visibility are rechecked under transaction locks.\r\n- The target must be enabled, not deleted and have a valid saved email. Send the confirmed profileRevision; recipients cannot be supplied by the caller.\r\n### Invitation\r\n- HTTP 202 with code `invitation-queued` means the mail queue transaction committed; it is not a delivery receipt.\r\n- Temporary delivery restriction: exact domains nortec.dk, kombinetech.com and arendt.dk receive directly; every other recipient goes to jens@arendt.dk. Cc/Bcc are cleared in every environment.\r\n- A single-use link to the configured portal expires after 30 minutes and uses ResetManagerPassword. No password, Enabled, Tabs, Kids or rights change when sending.\r\n- Language is en (default), da or es. Do not automatically retry an uncertain response: the mail may already be queued.\r\n### Errors\r\n- 400 invalid-manager-kid/invalid-invitation; 401 expired credentials; 403 missing rights/own-manager-permissions; 404 manager-not-found (including retention-hidden targets).\r\n- 409 profile-conflict: reload after a concurrent edit. 409 manager-invitation-invalid: enable the target, restore it or save a valid email first.\r\n- 429 invitation-rate: at most two invitations per target per 15 minutes per instance, separate from anonymous recovery. Follow Retry-After.\r\n- 503 manager-invitation-unavailable: storage/configuration failure. Request bodies and link tokens must never be logged.",
        "operationId": "InviteManager",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerInvitationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerInvitationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerInvitationRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerInvitationResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerInvitationResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerInvitationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/{managerKid}/kids": {
      "post": {
        "tags": [
          "ManagerKids"
        ],
        "summary": "Add or remove a tenant, whole-bank or single-location grant on an administrator.",
        "description": "Editing Tabs or Kids additionally requires independent Read and Write on that category in the caller snapshot, rechecked inside the transaction; accounting also requires Tabs Read/Write. Missing stored flags default to Read. Extra Create/Delete/Rename flags are stored independently but do not replace Write for these assignment operations.\r\n            ### Access\r\n           \r\n            - Requires an active manager, Managers1 (28), independent Managers Read and Write and explicit whole-tenant access.\r\n            - Own edits require being the sole active tenant-wide manager. All checks use the locked current Log7 snapshot, as for SetManagerPermission.\r\n            - The site supplies the tenant. Rejects foreign/noncanonical KIDs and resident, unit, tab or transaction identities.\r\n           \r\n            ### Selection\r\n           \r\n            - Use SearchBanks and SearchLocations to discover choices; their existing Read, scope and retention checks still apply.\r\n            - Adding a Bank grants the entire bank and replaces its narrower location entries. A Location grants only that location.\r\n            - Adding the site's Tenant KID selects all banks and replaces all narrower grants on this site. Already covered additions are no-ops.\r\n            - Removing a grant removes only that exact scope. Removing all-banks does not restore previously replaced narrower entries.\r\n            - Stored site-relative grants are resolved against this site. Unrelated foreign stored entries are preserved but grant no access here.\r\n            - Adding a bank/location requires an existing exact Settings scope in this site's Log24, checked inside the transaction. Removing a stale grant is allowed.\r\n            - Kids do not grant tabs or operation flags. No account, profile, tab or permission settings are changed.\r\n           \r\n            ### Saving and concurrency\r\n           \r\n            - Send kidsRevision as expectedRevision. One bank-zero Log7 history transaction reauthorizes, checks the revision, appends only changed values with the caller as actor and verifies the current-table trigger.\r\n            - Update the whole Kids display only after a valid 200 response. The response returns canonical site resourceGrants and the next kidsRevision.\r\n            - Removing your own whole-tenant access returns canEditKids=false; lock all editor controls. Actor/target sessions and directory indexes are invalidated even on uncertain outcomes.\r\n            - Existing session read caches on other API instances can live for up to 60 seconds; every write reauthorizes. The 12-second write deadline and sole-manager scan bound apply.\r\n           \r\n            ### Errors\r\n           \r\n            - 400 invalid-manager-kid or invalid-kid-change: malformed/foreign identity, unsupported scope or missing/invalid boolean/revision.\r\n            - 401 requires login; 403 uses the SetManagerPermission access codes. 404 manager-not-found includes retention-hidden managers; resource-not-found means the selected bank/location no longer exists.\r\n            - 409 kids-conflict: reread and review. invalid-stored-kids: malformed stored grants are not overwritten. kids-limit: adding would exceed 1,000 grants; removals and broader replacements remain allowed.\r\n            - 503 manager-kids-unavailable or timeout: keep the previous display and reread before a manual retry. Never automatically retry an uncertain commit.",
        "operationId": "SetManagerKid",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerKidChangeRequest"
              },
              "example": {
                "resourceKid": "A6Q1Eo7D0b1l",
                "enabled": true,
                "expectedRevision": "167C11B4EC0635E115AFA6F36013DB0F506D60EB34C5BB0943BC6489EA80C38D"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerKidChangeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerKidChangeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerKidChangeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerKidChangeResponse"
                },
                "example": {
                  "resourceGrants": [
                    {
                      "kid": "A6Q1Eo7D0b1l",
                      "scope": "Location"
                    }
                  ],
                  "kidsRevision": "4D1A710582348E7FE35291D7F5DF7DDB31FB0FF6A4F0B795F1FC54B3AC58E5D4",
                  "canEditKids": true
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerKidChangeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 409,
                  "title": "kids-conflict",
                  "code": "kids-conflict"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/forgot-password": {
      "post": {
        "tags": [
          "ManagerPasswordRecovery"
        ],
        "summary": "Request a manager password reset email.",
        "description": "### Recovery\r\n- Send the existing login email and optionally language `en`, `da` or `es`.\r\n- HTTP 202 with `code: accepted` is identical for unknown, ambiguous, disabled, deleted and throttled accounts.\r\n- The link expires after 30 minutes, is tenant/environment-bound and cannot be reused after a reset.\r\n- The API uses its configured PortalWeb:BaseUrl; callers cannot supply a redirect URL.\r\n### Temporary delivery lock\r\n- Exact domains nortec.dk, kombinetech.com and arendt.dk receive directly; every other recipient goes to jens@arendt.dk. Cc/Bcc are cleared. The submitted address still identifies the account.\r\n- Delivery is asynchronous through the existing Mails worker. A 202 does not guarantee delivery.\r\n### Errors\r\n- 400 invalid input; 429 IP limit (Retry-After); 503 unavailable configuration/storage. Never log request bodies or reset tokens.",
        "operationId": "RequestManagerPasswordReset",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerForgotPasswordRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerForgotPasswordRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerForgotPasswordRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/session/reset-password": {
      "post": {
        "tags": [
          "ManagerPasswordRecovery"
        ],
        "summary": "Replace a manager password using the emailed recovery token.",
        "description": "### Reset\r\n- Send token, password and confirmPassword. Use 12–128 printable ASCII characters with no leading/trailing spaces.\r\n- The new password must differ from the existing password; the shared legacy password hash is retained for login compatibility.\r\n- HTTP 200 `code: password-reset` means Log7 and a notification mail were committed together. Sign in normally afterwards.\r\n- Changing the password invalidates existing manager sessions when rechecked (other API instances may cache them for up to one minute).\r\n### Errors\r\n- 400 `invalid-password` for the password policy; 400 `invalid-reset` for expired, used, wrong-site or stale tokens, inactive accounts or an unchanged password.\r\n- 429 IP limit; 503 storage unavailable. Never automatically retry a reset with an uncertain outcome; try normal login or request a new link.\r\n- The temporary delivery restriction also applies to the notification: only nortec.dk, kombinetech.com and arendt.dk receive directly; everything else goes to jens@arendt.dk, without Cc/Bcc.",
        "operationId": "ResetManagerPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerResetPasswordRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerResetPasswordRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerResetPasswordRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPasswordResetResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/managers/{managerKid}/permission-role": {
      "post": {
        "tags": [
          "ManagerPermissionRoles"
        ],
        "summary": "Replace all nine permission categories with a predefined administrator role.",
        "description": "Every role replacement requires independent Read and Write on both Tabs and Kids in the caller snapshot, rechecked inside the transaction, because every preset replaces both permission masks. Missing stored flags default to Read. Extra Create/Delete/Rename flags are stored independently but do not replace Write for these assignment operations.\r\n            ### Access\r\n           \r\n            - Requires an active manager, Managers1 (28), independent Managers Read and Write, and a whole-tenant KID grant.\r\n            - Own edits require being the sole active tenant-wide manager. The same fresh transactional authorization as SetManagerPermission applies.\r\n           \r\n            The additional technical-support, tenant-installer and tenant-accounting presets currently grant all six flags (63) in all nine categories and preserve Tabs, matching operator.\r\n           \r\n            ### Presets\r\n           \r\n            | role | Bank | Location / Unit / User | Managers / Installer / Service |\r\n            | --- | --- | --- | --- |\r\n            | accounting (Regnskab) | Read (1) | Read (1) | None (0) |\r\n            | caretaker (Varmemester) | Read (1) | Read + Write (3) | None (0) |\r\n            | operator (Operatør) | All six flags (63) | All six flags (63) | All six flags (63) |\r\n           \r\n            - Replaces the whole matrix, including clearing existing extra flags. Accounting replaces Tabs with exactly Users2 (53), Account2 (2) and Settlement2 (40). Combine grants all six flags in all nine categories, selects every available tab (excluding None/Length), and grants the site's Tenant KID (all banks). Other roles preserve Tabs and Kids.\r\n            - Combine replaces narrower site grants, preserves unrelated foreign stored grants without granting access to them, and never changes account state or profile fields. Available tabs are selected once; future tabs are not automatically granted.\r\n            - A preset is a one-time assignment, not a stored or continuously enforced role. Individual checkboxes remain editable afterward if authorized.\r\n            - Applying accounting or caretaker to yourself removes Managers access. The response sets canEditPermissions=false; disable further editing. Operator enables all 54 checkboxes and retains Managers access.\r\n           \r\n            ### Concurrency and storage\r\n           \r\n            - Read GetManager first. Send expectedFlags for all nine categories, using explicit null for invalid stored values. Accounting and combine require expectedTabsRevision copied from tabsRevision; combine also requires expectedKidsRevision copied from kidsRevision.\r\n            - Requests must contain all nine categories, including Service, Tabs and Kids. Incomplete category sets are rejected.\r\n            - One serializable Log7 transaction validates every expected mask and applicable Tabs/Kids revisions before writing, appends only changed settings with the caller as actor, and verifies every current-table trigger. There are no partial permission/tab/resource updates.\r\n            - Every role response includes tabs, tabsRevision, canEditTabs, canEditPermissions, resourceGrants, kidsRevision and canEditKids. Validate the full response before changing the display; use the new revisions for the next edit.\r\n            - Update the whole display only after a valid 200 response. Session cache invalidation also applies to uncertain outcomes.\r\n           \r\n            ### Errors\r\n           \r\n            - 400 invalid-permission-role: unknown role, missing/extra categories, invalid masks or missing/invalid required revisions. Invalid tenant/KID returns invalid-manager-kid.\r\n            - 401 requires login. 403 uses the same permission codes as SetManagerPermission, including own-manager-permissions. 404 manager-not-found covers absent or retention-hidden records.\r\n            - 409 permission-conflict, tabs-conflict or kids-conflict: reload and review; nothing is partially saved. Accounting/combine return invalid-stored-tabs for malformed tabs; combine returns invalid-stored-kids for malformed grants, without overwriting them.\r\n            - 503 manager-permissions-unavailable or timeout: keep the old display and reread before manually retrying; do not automatically retry an uncertain commit. The existing 12-second deadline and sole-manager scan bound apply.",
        "operationId": "SetManagerPermissionRole",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerPermissionRoleRequest"
              },
              "example": {
                "role": "accounting",
                "expectedTabsRevision": "95853A22E6C30DA8B284412CD3468BD73827392CA44A2B06B7D05C3E18057DEB",
                "expectedFlags": {
                  "Managers": 0,
                  "Installer": 0,
                  "Service": 0,
                  "Bank": 1,
                  "Location": 1,
                  "Unit": 1,
                  "User": 1,
                  "Tabs": 1,
                  "Kids": 1
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerPermissionRoleRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerPermissionRoleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPermissionRoleResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPermissionRoleResponse"
                },
                "example": {
                  "role": "accounting",
                  "canEditPermissions": true,
                  "canEditTabs": true,
                  "tabsRevision": "704DB9F66325D40960364C5F9E935111640C8BC5B865658BAE9910516154B5C5",
                  "tabs": [
                    {
                      "id": 2,
                      "name": "Account2",
                      "iconKid": ""
                    },
                    {
                      "id": 40,
                      "name": "Settlement2",
                      "iconKid": ""
                    },
                    {
                      "id": 53,
                      "name": "Users2",
                      "iconKid": ""
                    }
                  ],
                  "operationPermissions": [
                    {
                      "resource": "Managers",
                      "level": "None",
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 0,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Installer",
                      "level": "None",
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 0,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Service",
                      "level": "None",
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 0,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Tabs",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Kids",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Bank",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Location",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Unit",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "User",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    }
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerPermissionRoleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 409,
                  "title": "tabs-conflict",
                  "code": "tabs-conflict"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/{managerKid}/permissions/{resource}": {
      "post": {
        "tags": [
          "ManagerPermissions"
        ],
        "summary": "Set one administrator permission checkbox, including your own if you are the sole active tenant-wide manager.",
        "description": "### Access\r\n            \r\n- Requires an active manager, **Managers1 (28)**, independent **Managers Read and Write**, and a **tenant-wide KID grant**.\r\n- Your **own** record is editable only when no other active, non-deleted manager has a whole-tenant KID grant; otherwise **403 own-manager-permissions**. All normal permissions above still apply.\r\n- The exception counts managers regardless of their tabs and operation flags, using bank-zero `Kids`, `Enabled` and `Deleted`. Bank/location-only grants do not count. The check runs inside the serializable write transaction with locks, never from a cached count or filtered directory page.\r\n- The actor's current Log7 account, credential stamp and access are rechecked inside the write transaction, without the session cache.\r\n            \r\n### Request and concurrency\r\n            \r\n- `resource`: Managers, Installer, Service, Bank, Location, Unit or User. Send a canonical manager KID on this site, bank zero.\r\n- `flag`: one numeric bit: Read=1, Write=2, Create=4, Delete=8, RenameExtrenatId=16 or Rename=32. `enabled` is the desired boolean state.\r\n- `expectedFlags` is required: send the category's flags from GetManager, including null for malformed stored values.\r\n- **409 permission-conflict:** reload and review before retrying. Only the selected bit changes; no bit implies another.\r\n            \r\n### Storage and errors\r\n            \r\n- Appends bank-zero Log7 history with the caller as actor; verifies the current Log7 trigger before commit. No-op requests append nothing.\r\n- Disabled targets can be edited. Missing or retention-hidden targets return **404 manager-not-found**.\r\n- **503 manager-permissions-unavailable:** write storage is unavailable, unconfigured or nontransactional, or the sole-manager scan exceeds 20,000 candidate scope records. Do not automatically retry an uncertain result; read GetManager first.\r\n- Success returns the authoritative category and invalidates the target's local session cache. Other instances' read caches may take up to 60 seconds; permission writes always use fresh authorization.",
        "operationId": "SetManagerPermission",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "resource",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerPermissionChangeRequest"
              },
              "example": {
                "flag": 2,
                "enabled": true,
                "expectedFlags": 1
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerPermissionChangeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerPermissionChangeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerOperationPermissionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerOperationPermissionResponse"
                },
                "example": {
                  "resource": "Bank",
                  "level": "3",
                  "canRead": true,
                  "canWrite": true,
                  "canCreate": false,
                  "flags": 3,
                  "canDelete": false,
                  "canRenameExternalId": false,
                  "canRename": false
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerOperationPermissionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 403,
                  "title": "own-manager-permissions",
                  "code": "own-manager-permissions"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 409,
                  "title": "permission-conflict",
                  "code": "permission-conflict"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/{managerKid}/profile/{field}": {
      "post": {
        "tags": [
          "ManagerProfiles"
        ],
        "summary": "Change Name, Organisation, Enabled, Deleted, RetentionDays, Icon or Email on an administrator.",
        "description": "### Access\r\n            \r\n- Requires an active account, Managers1 (28), independent Managers Read and Write and whole-tenant access. Own edits require the sole active tenant-wide manager exception. No extra Delete/Rename flag is required for these seven fields.\r\n- Every write rechecks the locked current actor account, credential stamp, tab and permissions, plus target existence and caller deletion retention. No cached edit hint grants access.\r\n            \r\n### Values and saving\r\n            \r\n- Read GetManager and send its profileRevision as expectedRevision. Field names are case-sensitive: Name, Organisation, Enabled, Deleted, RetentionDays, Icon, Email. Only the selected field changes.\r\n- Name/Organisation accept a string up to 200 characters with no control characters; empty clears the field. Whitespace and Unicode are preserved. RetentionDays accepts a nonnegative 32-bit integer. Enabled and Deleted accept true/false, not numbers or strings.\r\n- Email accepts one plain ASCII internet address, up to 254 characters. The local part has at most 64 characters without leading/trailing/consecutive dots. The domain requires at least two DNS labels, each 1–63 letters/digits/hyphens without a leading/trailing hyphen; international domains use punycode. Whitespace, controls, quoted local parts, address literals and display-name syntax return 400 invalid-profile-change before storage. This checks format, not mailbox existence. Case is preserved. This changes the login address without changing the password or revoking existing sessions; no verification or invitation message is sent. Existing duplicate-email login behavior is unchanged (email plus password must identify one account). The response includes the confirmed email.\r\n- Icon accepts an exact, case-sensitive eIcon name whose metadata is eIconSubject.Person. Read availableIcons from GetManager; an existing non-Person icon appears first for display only. Numeric values, URLs and new non-Person assignments return 400. Responses include saved icon and updated availableIcons. No-op clicks on the selected legacy icon should not send a write.\r\n- Enabled is stored as 1/0. Deleted=true stores the database server's current MS2000 (milliseconds since 2000-01-01 UTC); Deleted=false stores 0. Repeated true preserves the original deletion time. Clients cannot choose the timestamp; 1 is never written as a new deletion marker.\r\n- Write-time deletion retention and the confirmed canEditProfile hint use that same database clock, so clock differences cannot lock a freshly deleted target that remains within caller retention.\r\n- Uses the shared serializable bank-zero Log7 history writer with actor attribution and verified current-value trigger. Unchanged values add no history. Other settings and the password remain unchanged.\r\n- Update the UI only after a complete valid 200 response. Use its profileRevision for the next edit. canEditProfile=false locks all profile, permission, role and tab controls after own deactivation/deletion or loss of target visibility. Deleting a target with caller RetentionDays=0 hides it on the next read; restoration requires a caller whose existing retention includes it.\r\n            \r\n### Errors and freshness\r\n            \r\n- 400 invalid-manager-kid or invalid-profile-change: foreign/invalid identity, unknown field, invalid type/range, missing revision. 401 requires login. 403 uses the same codes as SetManagerPermission, including own-manager-permissions. 404 manager-not-found includes retention-hidden targets.\r\n- 409 profile-conflict: reread and review before retrying. The revision covers all seven profile fields, including their raw stored forms.\r\n- 503 manager-profile-unavailable or timeout: keep the prior UI and reread before a manual retry. A lost response may follow commit; never retry automatically.\r\n- Actor/target sessions and local directory indexes are invalidated even on uncertain outcomes. Other API instances may retain snapshots for up to 60 seconds. Existing sessions of a disabled/deleted target are denied on their next fresh authorization check. Every write rechecks immediately. The 12-second deadline and sole-manager scan bound apply.",
        "operationId": "SetManagerProfileField",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "field",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerProfileChangeRequest"
              },
              "example": {
                "value": "New display name",
                "expectedRevision": "BEF2DEB3350739954D4436BA548DE187DF9EC672687ED41C35D4C92C7274C0CD"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerProfileChangeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerProfileChangeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerProfileChangeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerProfileChangeResponse"
                },
                "example": {
                  "field": "Name",
                  "name": "New display name",
                  "organisation": "Example organisation",
                  "enabled": true,
                  "deleted": false,
                  "deletedMs2000": 0,
                  "deletedAt": null,
                  "retentionDays": 30,
                  "email": "manager@example.test",
                  "iconKid": "angel",
                  "availableIcons": [
                    "angel",
                    "astrologer",
                    "astronaut",
                    "athlete",
                    "baby",
                    "bicyclist",
                    "bookkeeper",
                    "boy",
                    "businessman",
                    "businessman2",
                    "businessperson",
                    "businessperson2",
                    "businessperson3",
                    "businesswoman",
                    "businesswoman2",
                    "caesar",
                    "clown",
                    "cook",
                    "criminal",
                    "delivery_man",
                    "delivery_man_parcel",
                    "devil",
                    "disability",
                    "doctor",
                    "dude1",
                    "dude2",
                    "dude3",
                    "dude4",
                    "dude5",
                    "dude6",
                    "engineer",
                    "face_scan",
                    "firefighter",
                    "genius",
                    "girl",
                    "graduate",
                    "guard",
                    "hipster",
                    "holmes",
                    "judge",
                    "lecture",
                    "magician",
                    "motorcyclist",
                    "nurse",
                    "pastor",
                    "person",
                    "pilot",
                    "policeman",
                    "policeman_bobby",
                    "pontifex",
                    "schoolboy",
                    "scientist",
                    "security_agent",
                    "senior_citizen",
                    "senior_citizen2",
                    "singer",
                    "soldier",
                    "spy",
                    "stockbroker",
                    "stockbroker2",
                    "surgeon",
                    "teacher",
                    "teacher_blackboard",
                    "terrorist",
                    "user",
                    "user_earth",
                    "user_glasses",
                    "user_headphones",
                    "user_headset",
                    "user_message",
                    "user_mobile_phone",
                    "user_monitor",
                    "user_smartphone",
                    "user_sunglasses",
                    "user_telephone",
                    "video_chat",
                    "video_chat2",
                    "woman",
                    "woman2",
                    "woman3",
                    "woman4",
                    "worker",
                    "worker2",
                    "user_mobilephone",
                    "accessibility",
                    "accessibility_new",
                    "accessible",
                    "accessible_forward",
                    "account_box",
                    "account_circle",
                    "assignment_ind",
                    "contact_page",
                    "face",
                    "face_unlock",
                    "manage_accounts",
                    "no_accounts",
                    "perm_contact_calendar",
                    "perm_identity",
                    "pregnant_woman",
                    "record_voice_over",
                    "rowing",
                    "settings_accessibility",
                    "transcribe",
                    "voice_over_off",
                    "contacts",
                    "contact_emergency",
                    "contact_mail",
                    "contact_phone",
                    "co_present",
                    "person_add_disabled",
                    "person_search",
                    "attribution",
                    "how_to_reg",
                    "remember_me",
                    "face_retouching_natural",
                    "face_retouching_off",
                    "portrait",
                    "badge",
                    "directions_run",
                    "directions_walk",
                    "person_pin",
                    "person_pin_circle",
                    "run_circle",
                    "streetview",
                    "transfer_within_a_station",
                    "support_agent",
                    "child_care",
                    "assist_walker",
                    "blind",
                    "downhill_skiing",
                    "elderly",
                    "elderly_woman",
                    "emoji_people",
                    "engineering",
                    "face_2",
                    "face_3",
                    "face_4",
                    "face_5",
                    "face_6",
                    "follow_the_signs",
                    "hiking",
                    "kayaking",
                    "kitesurfing",
                    "man",
                    "man_2",
                    "man_3",
                    "man_4",
                    "nordic_walking",
                    "paragliding",
                    "personal_injury",
                    "person_2",
                    "person_3",
                    "person_4",
                    "person_add",
                    "person_add_alt",
                    "person_add_alt_1",
                    "person_off",
                    "person_outline",
                    "person_remove",
                    "person_remove_alt_1",
                    "psychology",
                    "psychology_alt",
                    "scuba_diving",
                    "self_improvement",
                    "skateboarding",
                    "sledding",
                    "snowboarding",
                    "snowshoeing",
                    "sports_gymnastics",
                    "sports_handball",
                    "sports_martial_arts",
                    "surfing",
                    "woman_2",
                    "adam",
                    "businessman3",
                    "businessman_add",
                    "businessman_delete",
                    "businessman_edit",
                    "businessman_find",
                    "businessman_preferences",
                    "businessman_view",
                    "dude",
                    "nurse2",
                    "patient",
                    "pilot2",
                    "pirate",
                    "policeman_german",
                    "policeman_usa",
                    "robber",
                    "security_agent_add",
                    "security_agent_delete",
                    "security_agent_edit",
                    "stockbroker3",
                    "superhero",
                    "surgeon2",
                    "user2",
                    "user3",
                    "user_add",
                    "user_back",
                    "user_delete",
                    "user_edit",
                    "user_find",
                    "user_information",
                    "user_into",
                    "user_lock",
                    "user_new",
                    "user_preferences",
                    "user_refresh",
                    "user_time",
                    "user_view"
                  ],
                  "profileRevision": "BE70C7CEB4C321706DA4CAE5322405FFFE96E8AECB40662448DB47B67DED8FFD",
                  "canEditProfile": true
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerProfileChangeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 409,
                  "title": "profile-conflict",
                  "code": "profile-conflict"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/export-count": {
      "get": {
        "tags": [
          "Managers"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetManagerExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/{managerKid}": {
      "get": {
        "tags": [
          "Managers"
        ],
        "summary": "Read one administrator by canonical manager KID for a workspace shortcut.",
        "description": "### Access and identity\r\n            \r\n- Uses the same active-session, **Managers1**, **Managers Read** and **whole-tenant grant** requirements as `GetManagers`.\r\n- Reads only this site's `Log7`, bank zero. A bookmark is not permission.\r\n            \r\n### Visibility and result\r\n            \r\n- Disabled administrators remain visible; deletion retention still applies.\r\n- **HTTP 404:** the exact manager is absent or outside retention.\r\n- No passwords or activation credentials are returned.\r\n- `canEditPermissions` is a display hint, never authorization. Your own record is unlocked only for the sole active manager with whole-tenant access and Managers Write; writes recheck this inside the transaction.\r\n- `availableTabs` lists every known eTab except None/Length, with numeric aliases deduplicated and metadata ordering. Includes legacy/unimplemented pages; it does not grant access. Only GetManager includes this catalog.\r\n- `availableIcons` is included only in GetManager: all eIcon names with eIconSubject.Person metadata, ordered by numeric identity. The current display icon is prepended when outside this catalog. It is display-only in that case; new assignments must be Person icons. Missing/unsafe stored filenames display as the user icon without rewriting storage.\r\n- `tabs` remains the selected set. `tabsRevision` covers the complete stored setting, including unknown numbers. Use SetManagerTab with this revision to toggle one tab. `canEditTabs` follows the same fresh-write policy as permission editing.\r\n- `canEditProfile` follows the same policy. `profileRevision` covers Name, Organisation, Enabled, Deleted, RetentionDays, Icon and Email. Use SetManagerProfileField to change one field; deletion time is set by the server in MS2000.\r\n- `operationPermissions` also includes **Service**, from `PermissionService2` (3017). Its flags are independent and do not grant login or permissions in other categories.\r\n- `operationPermissions` includes **Installer** from `PermissionInstaller2`, using the same independent flags and defaults as the other six categories. GetInstallers requires Installer Read, Installers1 and tenant-wide access; GetInstaller uses the same read access and SetInstallerIcon additionally requires Installer Write.",
        "operationId": "GetManager",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "description": "Canonical manager KID in this site's manager range, bank zero.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerDirectoryItem"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerDirectoryItem"
                },
                "example": {
                  "kid": "A6Q46o3B9ACA01h",
                  "name": "Example administrator",
                  "iconKid": "user",
                  "email": "admin@example.test",
                  "organisation": "Example organisation",
                  "enabled": true,
                  "deleted": false,
                  "deletedAt": null,
                  "lastActiveAt": "2026-09-25T12:34:56.789+00:00",
                  "retentionDays": 30,
                  "canEditPermissions": true,
                  "canEditTabs": true,
                  "isCurrentManager": false,
                  "canEditProfile": true,
                  "profileRevision": "61461452DAE1676B1E2EA99320D987DF7FB1AB26219A5A0CD3C748F944013A51",
                  "tabsRevision": "B8FB8869A5281D0DAD8A15E82DB9A7E6F1C6C89611DB79A276E557F7A6BDEA3E",
                  "operationPermissions": [
                    {
                      "resource": "Managers",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Bank",
                      "level": "3",
                      "canRead": true,
                      "canWrite": true,
                      "canCreate": false,
                      "flags": 3,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Location",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Unit",
                      "level": "None",
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 0,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "User",
                      "level": "48",
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 48,
                      "canDelete": false,
                      "canRenameExternalId": true,
                      "canRename": true
                    },
                    {
                      "resource": "Installer",
                      "level": "5",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": true,
                      "flags": 5,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Service",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Tabs",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Kids",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "flags": 1,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    }
                  ],
                  "resourceGrants": [
                    {
                      "kid": "A6Q14o7D0b",
                      "scope": "Bank"
                    }
                  ],
                  "tabs": [
                    {
                      "id": 28,
                      "name": "Managers1",
                      "iconKid": ""
                    }
                  ],
                  "availableTabs": [
                    {
                      "id": 1,
                      "name": "Access1",
                      "iconKid": ""
                    },
                    {
                      "id": 2,
                      "name": "Account2",
                      "iconKid": ""
                    },
                    {
                      "id": 3,
                      "name": "Bags1",
                      "iconKid": ""
                    },
                    {
                      "id": 4,
                      "name": "Bank1",
                      "iconKid": ""
                    },
                    {
                      "id": 6,
                      "name": "Banks3",
                      "iconKid": ""
                    },
                    {
                      "id": 7,
                      "name": "Book1",
                      "iconKid": ""
                    },
                    {
                      "id": 8,
                      "name": "Bookings1",
                      "iconKid": ""
                    },
                    {
                      "id": 9,
                      "name": "ChargePoint1",
                      "iconKid": ""
                    },
                    {
                      "id": 10,
                      "name": "Checklist1",
                      "iconKid": ""
                    },
                    {
                      "id": 11,
                      "name": "Closed1",
                      "iconKid": ""
                    },
                    {
                      "id": 12,
                      "name": "Dashboard1",
                      "iconKid": ""
                    },
                    {
                      "id": 13,
                      "name": "DebitCredit1",
                      "iconKid": ""
                    },
                    {
                      "id": 14,
                      "name": "DeleteUnit1",
                      "iconKid": ""
                    },
                    {
                      "id": 15,
                      "name": "Doors5",
                      "iconKid": ""
                    },
                    {
                      "id": 16,
                      "name": "Errors1",
                      "iconKid": ""
                    },
                    {
                      "id": 17,
                      "name": "Errors2",
                      "iconKid": ""
                    },
                    {
                      "id": 18,
                      "name": "Errors3",
                      "iconKid": ""
                    },
                    {
                      "id": 19,
                      "name": "FlexSMS1",
                      "iconKid": ""
                    },
                    {
                      "id": 20,
                      "name": "GPS1",
                      "iconKid": ""
                    },
                    {
                      "id": 21,
                      "name": "Global1",
                      "iconKid": ""
                    },
                    {
                      "id": 22,
                      "name": "Import1",
                      "iconKid": ""
                    },
                    {
                      "id": 23,
                      "name": "Importuser1",
                      "iconKid": ""
                    },
                    {
                      "id": 24,
                      "name": "Jobs1",
                      "iconKid": ""
                    },
                    {
                      "id": 25,
                      "name": "Live3",
                      "iconKid": ""
                    },
                    {
                      "id": 26,
                      "name": "Login1",
                      "iconKid": ""
                    },
                    {
                      "id": 27,
                      "name": "Logout1",
                      "iconKid": ""
                    },
                    {
                      "id": 29,
                      "name": "More1",
                      "iconKid": ""
                    },
                    {
                      "id": 30,
                      "name": "Offline1",
                      "iconKid": ""
                    },
                    {
                      "id": 31,
                      "name": "Offline2",
                      "iconKid": ""
                    },
                    {
                      "id": 32,
                      "name": "Offline3",
                      "iconKid": ""
                    },
                    {
                      "id": 33,
                      "name": "Orders1",
                      "iconKid": ""
                    },
                    {
                      "id": 34,
                      "name": "Process1",
                      "iconKid": ""
                    },
                    {
                      "id": 35,
                      "name": "QR1",
                      "iconKid": ""
                    },
                    {
                      "id": 36,
                      "name": "Release1",
                      "iconKid": ""
                    },
                    {
                      "id": 37,
                      "name": "RetailPrices1",
                      "iconKid": ""
                    },
                    {
                      "id": 38,
                      "name": "Robert1",
                      "iconKid": ""
                    },
                    {
                      "id": 39,
                      "name": "SMS1",
                      "iconKid": ""
                    },
                    {
                      "id": 40,
                      "name": "Settlement2",
                      "iconKid": ""
                    },
                    {
                      "id": 41,
                      "name": "Soap1",
                      "iconKid": ""
                    },
                    {
                      "id": 42,
                      "name": "SoapCentral",
                      "iconKid": ""
                    },
                    {
                      "id": 43,
                      "name": "SoapCentral1",
                      "iconKid": ""
                    },
                    {
                      "id": 44,
                      "name": "SoapDosage1",
                      "iconKid": ""
                    },
                    {
                      "id": 45,
                      "name": "Stat1",
                      "iconKid": ""
                    },
                    {
                      "id": 46,
                      "name": "Statistics1",
                      "iconKid": ""
                    },
                    {
                      "id": 47,
                      "name": "Statistics2",
                      "iconKid": ""
                    },
                    {
                      "id": 48,
                      "name": "Tools1",
                      "iconKid": ""
                    },
                    {
                      "id": 49,
                      "name": "UnitCount1",
                      "iconKid": ""
                    },
                    {
                      "id": 51,
                      "name": "User2",
                      "iconKid": ""
                    },
                    {
                      "id": 52,
                      "name": "User3",
                      "iconKid": ""
                    },
                    {
                      "id": 53,
                      "name": "Users2",
                      "iconKid": ""
                    },
                    {
                      "id": 54,
                      "name": "WashDoc1",
                      "iconKid": ""
                    },
                    {
                      "id": 55,
                      "name": "WashDoc3",
                      "iconKid": ""
                    },
                    {
                      "id": 56,
                      "name": "evaskeriusers1",
                      "iconKid": ""
                    },
                    {
                      "id": 57,
                      "name": "BookWeek1",
                      "iconKid": ""
                    },
                    {
                      "id": 58,
                      "name": "Bank2",
                      "iconKid": ""
                    },
                    {
                      "id": 59,
                      "name": "OutOfOrder1",
                      "iconKid": ""
                    },
                    {
                      "id": 61,
                      "name": "LoginFail1",
                      "iconKid": ""
                    },
                    {
                      "id": 62,
                      "name": "SignUp1",
                      "iconKid": ""
                    },
                    {
                      "id": 63,
                      "name": "Privacy1",
                      "iconKid": ""
                    },
                    {
                      "id": 64,
                      "name": "DocIdsCurrent1",
                      "iconKid": ""
                    },
                    {
                      "id": 67,
                      "name": "GlobalInfo1",
                      "iconKid": ""
                    },
                    {
                      "id": 69,
                      "name": "DevUnit1",
                      "iconKid": ""
                    },
                    {
                      "id": 70,
                      "name": "DevLocation1",
                      "iconKid": ""
                    },
                    {
                      "id": 71,
                      "name": "DevBank1",
                      "iconKid": ""
                    },
                    {
                      "id": 72,
                      "name": "DevTenant1",
                      "iconKid": ""
                    },
                    {
                      "id": 73,
                      "name": "Map1",
                      "iconKid": ""
                    },
                    {
                      "id": 74,
                      "name": "NayaxStreaks1",
                      "iconKid": ""
                    },
                    {
                      "id": 75,
                      "name": "WashDoc2",
                      "iconKid": ""
                    },
                    {
                      "id": 76,
                      "name": "Test1",
                      "iconKid": ""
                    },
                    {
                      "id": 78,
                      "name": "Log1",
                      "iconKid": ""
                    },
                    {
                      "id": 79,
                      "name": "FlexControllerFollower",
                      "iconKid": ""
                    },
                    {
                      "id": 80,
                      "name": "TenantStatus1",
                      "iconKid": ""
                    },
                    {
                      "id": 81,
                      "name": "Hosting1",
                      "iconKid": ""
                    },
                    {
                      "id": 82,
                      "name": "Logs1",
                      "iconKid": ""
                    },
                    {
                      "id": 83,
                      "name": "ForgotPassword1",
                      "iconKid": ""
                    },
                    {
                      "id": 84,
                      "name": "Camera1",
                      "iconKid": ""
                    },
                    {
                      "id": 5,
                      "name": "Banks2",
                      "iconKid": ""
                    },
                    {
                      "id": 65,
                      "name": "Locations1",
                      "iconKid": ""
                    },
                    {
                      "id": 66,
                      "name": "Terminals1",
                      "iconKid": ""
                    },
                    {
                      "id": 50,
                      "name": "Units1",
                      "iconKid": ""
                    },
                    {
                      "id": 60,
                      "name": "Services1",
                      "iconKid": ""
                    },
                    {
                      "id": 28,
                      "name": "Managers1",
                      "iconKid": ""
                    },
                    {
                      "id": 68,
                      "name": "Installers1",
                      "iconKid": ""
                    },
                    {
                      "id": 77,
                      "name": "UserFinder1",
                      "iconKid": ""
                    }
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerDirectoryItem"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 403,
                  "title": "missing-tenant-access",
                  "code": "missing-tenant-access"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 404,
                  "title": "manager-not-found",
                  "code": "manager-not-found"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/{managerKid}/same-email": {
      "get": {
        "tags": [
          "Managers"
        ],
        "summary": "List other visible administrators with the same stored email as this manager.",
        "description": "Same authorization as GetManager. Exact trimmed, ordinal case-insensitive matching within this tenant; excludes the source and empty email. Disabled accounts are included; caller deletion retention applies. Candidate index is at most 60 seconds old, bounded to 20,000 entries; at most 100 matching candidates are reread from current Log7 before returning. Larger matches return 503 manager-directory-too-large, never a partial list. 404 when source is absent or hidden. 12-second deadline. No credentials returned.",
        "operationId": "GetManagersWithSameEmail",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ManagerEmailMatch"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ManagerEmailMatch"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ManagerEmailMatch"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/login": {
      "post": {
        "tags": [
          "ManagerSession"
        ],
        "summary": "Log in with manager email/password or manager username/API key.",
        "description": "### Sign in\r\n            \r\n- Send exactly one complete pair: email/password or kid/apiKey, over HTTPS. Never hash credentials in the client.\r\n- The kid field accepts the manager Kid.ToUserId username (tenant.0-userId) or canonical bank-zero manager KID on this site. API keys use eSetting.ApiKeyHash, never Password.\r\n- API-key login performs no duplicate-account cleanup. Inactive accounts and invalid keys return 401.\r\n- Key replacement revokes key-authenticated sessions within 60 seconds; renewal preserves the key proof.\r\n- Use `accessToken` in `Authorization: Bearer {accessToken}` when calling `GetCurrentManager`.\r\n- The opaque token lasts **259,200 seconds (three days)**. Do not decode it as a JWT.\r\n- Before expiry, use `RenewManagerSession` to replace it after user activity. No separate refresh token is issued.\r\n            \r\n### Tenant and access\r\n            \r\n- The API site's configuration selects the tenant, not the request.\r\n- Credentials and current manager settings come from the site's `A{TenantId:D4}.Log7`, bank zero. Tenant 166 uses `A0166`; there is no fallback to another tenant.\r\n- Missing Tabs or Kids do not prevent login. Inspect `GetCurrentManager` and explain missing access in your UI.\r\n- If several managers match both email and password, the active, non-deleted manager with the newest `eSetting.Alive` krumb MS2000 wins.\r\n  Missing/invalid activity ranks last; equal activity (including all unknown) is resolved by the lowest UserId.\r\n  Login atomically clears Password on the other matching accounts; accounts with different passwords are unchanged.\r\n  Without an active match, no cleanup occurs. Grants are never merged. Read `GetCurrentManager` for the selected identity.\r\n            \r\n### Errors and diagnostics\r\n            \r\n- **HTTP 401:** incorrect credentials.\r\n- After password verification, **HTTP 403** distinguishes `disabled`, `deleted` and `account-settings`.\r\n- **HTTP 429:** wait for `Retry-After` before another attempt.\r\n- **HTTP 503:** credential storage or atomic duplicate cleanup is unavailable (also for more than 100 matching rows).\r\n  Do not automatically retry an uncertain cleanup result. No token is issued before cleanup commits.\r\n- Rejections may create sanitized internal diagnostics; these expose no additional account information to clients.\r\n- Failed attempts include the API-observed IP. Server-side portals may send `X-Portal-Login-Client-IP` as **untrusted diagnostic metadata only**; it never changes authorization or rate limits.",
        "operationId": "LoginManager",
        "parameters": [
          {
            "name": "X-Portal-Login-Client-IP",
            "in": "header",
            "description": "Optional IPv4/IPv6 address observed by a server-side portal for its browser client. Logged only as caller-reported metadata on failed logins, alongside the API-observed IP. Invalid/multiple values are ignored. Never changes authentication, tenant scope, local-login checks or rate limits.",
            "schema": {
              "maxLength": 45,
              "type": "string"
            },
            "example": "192.0.2.10"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerLoginRequest"
              },
              "example": {
                "email": "manager@example.test",
                "password": "<your password>"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerLoginRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerLoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerSessionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerSessionResponse"
                },
                "example": {
                  "accessToken": "<opaque access token>",
                  "expiresIn": 259200,
                  "tokenType": "Bearer"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerSessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerLoginErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerLoginErrorResponse"
                },
                "example": {
                  "code": "disabled"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerLoginErrorResponse"
                }
              }
            }
          },
          "413": {
            "description": "Content Too Large",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported Media Type",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/session/renew": {
      "post": {
        "tags": [
          "ManagerSession"
        ],
        "summary": "Renew an unexpired manager session for three days.",
        "description": "Send the current bearer token and no request body. The site's current account state and password\r\nstamp are revalidated through the same bounded (at most 60-second) snapshot as other operations.\r\nStore the returned accessToken and expiresIn in place of the old session. Ordinary API requests\r\ndo not extend token expiry. Renew only after user activity, not from an unattended keep-alive timer.\r\nExpired/revoked sessions require login (401); unavailable account storage returns 503.\r\nRenewal preserves local-development restrictions and grants no additional Tab/KID/operation access.\r\nOlder token copies retain their original expiry; no separate refresh token is issued.",
        "operationId": "RenewManagerSession",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerSessionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerSessionResponse"
                },
                "example": {
                  "accessToken": "<replacement access token>",
                  "expiresIn": 259200,
                  "tokenType": "Bearer"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerSessionResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me": {
      "get": {
        "tags": [
          "ManagerSession"
        ],
        "summary": "Get your profile, permitted tabs, bank/location access, and operation permissions.",
        "description": "### Profile and navigation\r\n            \r\n- Returns the manager information used by the portal's overview cards in **one request**. Reuse it for all cards and navigation on the current view.\r\n- Optional `gravatarUrl` is the preferred profile picture. Use `iconKid` when null or the image fails (including 404); it is a display hint, never an access grant.\r\n- Empty `tabs` means no permitted pages. `hasBankAccess=false` means no banks or locations on this site.\r\n- `Banks2` (tab 5) is included when granted, like other recognized tabs.\r\n- `tabs` and `tabDetails` follow `AttributeMetaSortOrder` on `eTab`, then numeric tab ID. Missing sort metadata has order zero.\r\n            \r\n### Permissions\r\n            \r\n- Missing permission settings default to **Read**. An invalid nonempty value yields `level=null` and all rights false.\r\n- Operation permissions and tab ordering never expand `resourceGrants` or grant additional pages.\r\n- No manager ID or tenant override is accepted.\r\n- `operationPermissions` also includes **Service**, from `PermissionService2` (3017). Its flags are independent and do not grant login or permissions in other categories.\r\n- `operationPermissions` includes **Installer**, from `PermissionInstaller2`, alongside Managers, Bank, Location, Unit and User. GetInstallers requires Installer Read, Installers1 and tenant-wide access; GetInstaller uses the same read access and SetInstallerIcon additionally requires Installer Write; these flags grant no other category's permissions.\r\n            \r\n### Caching and database indicator\r\n            \r\n- Rights and account state are cached for at most **60 seconds** per API instance. Requests do not extend this; do not poll continuously.\r\n- `databaseAccess` is an informational Log7 read/append check shared for **10 minutes**, or **1 minute** when unknown.\r\n- The indicator grants no manager rights, executes no writes and does not verify every bank, trigger or operation.\r\n            \r\n### Errors\r\n            \r\n- **HTTP 401:** expired/revoked token or inactive account.\r\n- **HTTP 503:** permission data is unavailable.",
        "operationId": "GetCurrentManager",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerProfileResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerProfileResponse"
                },
                "example": {
                  "kid": "3E7Q46o3B9ACA01h",
                  "name": "Example manager",
                  "organisation": "Example organisation",
                  "iconKid": "house",
                  "retentionDays": 30,
                  "themeMode": 0,
                  "tabs": [
                    4,
                    12
                  ],
                  "hasBankAccess": true,
                  "databaseAccess": {
                    "canWrite": false,
                    "checkedAtUtc": "2026-09-25T12:00:00Z"
                  },
                  "tabDetails": [
                    {
                      "id": 4,
                      "name": "Bank1",
                      "iconKid": "bank_building"
                    },
                    {
                      "id": 12,
                      "name": "Dashboard1",
                      "iconKid": "dashboard"
                    }
                  ],
                  "resourceGrants": [
                    {
                      "kid": "3E7Q14o2Ab",
                      "scope": "Bank"
                    }
                  ],
                  "navigationBanks": [
                    {
                      "kid": "3E7Q14o2Ab",
                      "name": "Example bank",
                      "iconKid": "house"
                    }
                  ],
                  "operationPermissions": [
                    {
                      "resource": "Managers",
                      "level": "Read",
                      "flags": 1,
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Bank",
                      "level": "Read",
                      "flags": 1,
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false
                    },
                    {
                      "resource": "Location",
                      "level": "3",
                      "flags": 3,
                      "canRead": true,
                      "canWrite": true,
                      "canCreate": false
                    },
                    {
                      "resource": "Unit",
                      "level": "7",
                      "flags": 7,
                      "canRead": true,
                      "canWrite": true,
                      "canCreate": true
                    },
                    {
                      "resource": "User",
                      "level": null,
                      "flags": null,
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": false
                    },
                    {
                      "resource": "Installer",
                      "level": "Read",
                      "flags": 1,
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    },
                    {
                      "resource": "Service",
                      "level": "Read",
                      "flags": 1,
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false,
                      "canDelete": false,
                      "canRenameExternalId": false,
                      "canRename": false
                    }
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerProfileResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/signup": {
      "post": {
        "tags": [
          "ManagerSignUp"
        ],
        "summary": "Create a pending manager with a password and queue a manager-bound verification email.",
        "description": "Name/organisation are required, max 200 characters without controls. Password and confirmPassword must match,\r\n            with 12–128 printable ASCII characters and no leading/trailing spaces. No tenant or permission selectors are accepted.\r\n            Stores the profile, password hash, pending marker, Enabled=0 and all operation masks=0 in Log7, then queues a Mails row\r\n            with the allocated manager UserId in the same transaction under the tenant manager-create lock. Mail failure rolls back creation.\r\n            Resubmission for an untouched pending account with the same password refreshes its proof and mail without allocating another ID.\r\n            Existing active/disabled non-signup accounts and wrong passwords get the same silent 202 accepted response without changes/mail.\r\n            The proof expires in 30 minutes. Allowed delivery domains: nortec.dk, kombinetech.com and arendt.dk; others: 400 email-delivery-restricted.\r\n            202 accepted confirms processing, not delivery. Email throttling is silent.\r\n            Language must be exactly lowercase en, da or es when supplied; omitted/null uses English.\r\n            Empty strings, whitespace, regional tags, uppercase and other values return 400 ValidationProblemDetails with errors.Language before account creation or mail queueing.\r\n            Never log request bodies, passwords or tokens; never retry an uncertain storage outcome automatically.",
        "operationId": "RequestManagerSignUp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerSignUpRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerSignUpRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerSignUpRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/session/signup-confirmation": {
      "post": {
        "tags": [
          "ManagerSignUp"
        ],
        "summary": "Verify the email and activate only the manager already created by self-registration.",
        "description": "Only token is accepted; no password or profile input. Explicit POST is required. The 30-minute proof is tenant/environment-bound\r\n            and checked against locked email, password, pending-proof and Enabled revisions. Deleted or non-pending accounts and changed proof-bound values are rejected.\r\n            Atomically replaces the pending marker with the existing email-version proof and sets Enabled=1; no permissions, profile or password changes.\r\n            Authorized administrators may separately assign or revoke access while verification is pending; confirmation preserves those changes and grants no permissions itself.\r\n            200 email-verified issues no session; sign in normally afterwards. Reused, expired or invalid proof: 400 invalid-signup-token.\r\n            503 signup-unavailable can have an uncertain outcome; do not automatically retry.",
        "operationId": "ConfirmManagerSignUp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerSignUpConfirmation"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerSignUpConfirmation"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerSignUpConfirmation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/managers/{managerKid}/tabs/{tabId}": {
      "post": {
        "tags": [
          "ManagerTabs"
        ],
        "summary": "Assign or remove one available eTab on an administrator.",
        "description": "Editing Tabs or Kids additionally requires independent Read and Write on that category in the caller snapshot, rechecked inside the transaction; accounting also requires Tabs Read/Write. Missing stored flags default to Read. Extra Create/Delete/Rename flags are stored independently but do not replace Write for these assignment operations.\r\n            ### Access and choices\r\n           \r\n            - Requires an active account, Managers1 (28), independent Managers Read and Write and a whole-tenant KID grant. Every check uses the locked current actor snapshot in the write transaction.\r\n            - Own edits require the sole active tenant-wide manager exception; otherwise 403 own-manager-permissions. This is the same policy as SetManagerPermission.\r\n            - GetManager returns availableTabs: all recognized numeric eTab values except None/Length, aliases deduplicated. Labels/names derive from enum metadata; existing and unimplemented pages are included.\r\n            - Tabs grant page access only. Kids, operation permissions and account status are unchanged.\r\n           \r\n            ### Saving and concurrency\r\n           \r\n            - Send enabled plus the exact tabsRevision as expectedRevision. A stale revision returns 409 tabs-conflict; reread and review before trying again.\r\n            - Only the requested tab changes. Unknown numeric IDs and unrelated values are preserved. Malformed JSON or non-integer values return 409 invalid-stored-tabs without overwriting the setting.\r\n            - Writes use one serializable bank-zero Log7 history append with the caller as actor and verified current-table trigger. A no-op appends nothing. No writes to legacy tables.\r\n            - Update selected icons only after a valid successful response. Removing your own Managers1 grant returns canEditTabs=false and canEditPermissions=false; lock all editor controls.\r\n            - Actor/target session caches are invalidated even on uncertain outcomes; other instances may retain read snapshots for up to 60 seconds. Every write rechecks fresh authorization. The existing 12-second deadline and sole-manager scan bound apply.\r\n           \r\n            ### Errors\r\n           \r\n            - 400 invalid-manager-kid or invalid-tab-change covers foreign/malformed identities, unavailable IDs and missing inputs. 401 requires login.\r\n            - 403 uses the same access codes as SetManagerPermission. 404 manager-not-found covers absent or retention-hidden targets.\r\n            - 503 manager-tabs-unavailable or timeout: keep the previous selection; reread before a manual retry because a lost response may follow commit. Never automatically retry.",
        "operationId": "SetManagerTab",
        "parameters": [
          {
            "name": "managerKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tabId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerTabChangeRequest"
              },
              "example": {
                "enabled": true,
                "expectedRevision": "B8FB8869A5281D0DAD8A15E82DB9A7E6F1C6C89611DB79A276E557F7A6BDEA3E"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerTabChangeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerTabChangeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerTabChangeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerTabChangeResponse"
                },
                "example": {
                  "tabs": [
                    {
                      "id": 8,
                      "name": "Bookings1",
                      "iconKid": ""
                    },
                    {
                      "id": 28,
                      "name": "Managers1",
                      "iconKid": ""
                    }
                  ],
                  "tabsRevision": "162B4D892F7B0465E7C096F7F7E4C02DE0D0856654950A5D6B08529DB578FC90",
                  "canEditTabs": true,
                  "canEditPermissions": true
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerTabChangeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 409,
                  "title": "tabs-conflict",
                  "code": "tabs-conflict"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/theme": {
      "post": {
        "tags": [
          "ManagerTheme"
        ],
        "summary": "Save your own theme preference.",
        "description": "### Value and access\r\n            \r\n- Send numeric `eThemeMode`: **System = 0**, **Light = 1**, **Dark = 2**.\r\n- Requires an active manager session and matching credential stamp on this site. No manager, KID or tenant selector is accepted.\r\n- This own-account preference needs no bank Tab, KID grant or resident-write permission, and grants no business access.\r\n            \r\n### Storage and refresh\r\n            \r\n- Writes require the site's configured write connection.\r\n- Repeating the stored value creates no additional history.\r\n- Success invalidates this API instance's profile cache. Other instances may take up to **60 seconds** to refresh.\r\n- `GetCurrentManager` returns `themeMode`, defaulting to **System** when absent or invalid.",
        "operationId": "SetCurrentManagerTheme",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerThemeRequest"
              },
              "example": {
                "themeMode": 2
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerThemeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ManagerThemeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerThemeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerThemeResponse"
                },
                "example": {
                  "themeMode": 2
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagerThemeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/nearest": {
      "get": {
        "tags": [
          "NearestLocations"
        ],
        "summary": "Get up to ten authorized locations nearest to a supplied position.",
        "description": "Latitude and longitude are finite decimal degrees in [-90,90] and [-180,180].\r\n            Requires an active tenant-bound manager, Locations1, independent Bank Read and Location Read, and resource grants.\r\n            Reads only visible enabled Log24 locations with valid nonzero coordinates, preserving manager retention and scope.\r\n            SQL orders by great-circle distance before LIMIT 10; bank/location identities break ties. No radius limit or text filter.\r\n            Distances are straight-line metres, not driving distances. Locations lacking valid coordinates are omitted.\r\n            Position is used only for this lookup; it is not written to the database or returned. Do not log coordinate query strings.\r\n            400 invalid-position; 401 stale/inactive session; 403 missing-locations-access; 503 locations-unavailable.\r\n            Empty authorized results return 200 with an empty array. No-store; 12-second deadline.",
        "operationId": "GetNearestLocations",
        "parameters": [
          {
            "name": "latitude",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "longitude",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NearestLocationItem"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NearestLocationItem"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NearestLocationItem"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/managers/count": {
      "get": {
        "tags": [
          "PeopleDirectoryCounts"
        ],
        "summary": "Count all visible administrators, independently of the current page/filter.",
        "description": "Requires Managers1, Managers Read and whole-tenant access. Includes disabled accounts and\r\n            deletions within the caller's RetentionDays, like GetManagers. Reuses the 60-second, 20,000-identity\r\n            bounded directory index. No estimate is returned when that bound is exceeded. No-store.",
        "operationId": "GetManagerCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/installers/count": {
      "get": {
        "tags": [
          "PeopleDirectoryCounts"
        ],
        "summary": "Count all visible installers, independently of the current page/filter.",
        "description": "Requires Installers1, Installer Read and whole-tenant access. Includes disabled accounts and\r\n            deletions within the caller's RetentionDays, like GetInstallers. Reuses the existing 60-second,\r\n            at-most-999-identity directory index. No-store. Both counts recheck current session access.",
        "operationId": "GetInstallerCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/profile": {
      "get": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Read your own personal settings and available person icons.",
        "description": "### Access and fields\r\n- Requires an active manager bearer session on this tenant with a current credential stamp. No Tabs, Kids or Managers Write are needed.\r\n- Returns name, organisation, icon, email, emailVerified, numeric themeMode (System=0, Light=1, Dark=2), iconSet (g or line; default g), retentionDays, revision and availableIcons.\r\n- retentionDays is the number of days deleted records remain visible within your existing access; 0 hides deleted records. Missing/invalid stored values return 0.\r\n- emailVerified is proof of this exact current email log version, not an old or manually assigned flag.\r\n- No target manager or tenant selector is accepted. Passwords and internal verification data are never returned.\r\n- Reads use the site's read connection only; no configured write connection or MySQL write privilege is required.\r\n### Errors\r\n- 401 stale/inactive session; 503 unavailable storage. Responses are not cacheable.",
        "operationId": "GetMyManagerProfile",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerProfile"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerProfile"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerProfile"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/api-key": {
      "get": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Read your own API-key configuration status and revision without exposing credentials.",
        "description": "Requires a current active tenant-bound manager session. No administrative permissions required.\r\n            Reads bank-zero Log7 ApiKeyHash for the authenticated manager only. 401 invalid session; 503 unavailable storage. No-store.",
        "operationId": "GetMyManagerApiKey",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerApiKey"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerApiKey"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerApiKey"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Generate your own API key and commit its hash to eSetting.ApiKeyHash.",
        "description": "Send revision from GetMyManagerApiKey. Generates kt_ plus 64 random ASCII letters/digits.\r\n            Uses the existing password-compatible hash, stored only in bank-zero Log7 ApiKeyHash; Password is preserved.\r\n            Active manager, tenant and credential stamp are checked again inside the transaction. No account selector or permission grant.\r\n            Plaintext appears once, only after commit acknowledgement. Never log the response or store it in browser storage.\r\n            A replacement invalidates the previous key. 400 invalid-api-key-revision; 401 inactive/stale session;\r\n            409 api-key-conflict: reread before retrying; 503 uncertain/unavailable storage: never retry automatically.",
        "operationId": "GenerateMyManagerApiKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalApiKeyRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalApiKeyRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalApiKeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalApiKeyResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalApiKeyResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalApiKeyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/tabs": {
      "get": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Read your own tab selection, available tabs and editing eligibility.",
        "description": "Requires an active tenant-bound manager session. Returns kid, tabs, availableTabs, revision and canEdit.\r\nEach tab has its stable numeric id and enum name. CanEdit requires an explicit all-banks grant for this site's tenant.\r\nBank/location grants, even several covering current banks, do not qualify. No Managers tab or Managers Write is required.\r\nThe catalog includes unimplemented tabs; choosing one does not implement its page or grant business operations.\r\nReading uses the site's read connection only. CanEdit describes manager authorization; saving still requires database write access.\r\n401 invalid/revoked session; 503 unavailable storage. No cache and no credential fields.",
        "operationId": "GetMyManagerTabs",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerTabs"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerTabs"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerTabs"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/tabs/{tabId}": {
      "post": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Select or deselect one of your own tabs when you have access to all banks.",
        "description": "Send enabled (boolean) and revision from GetMyManagerTabs. tabId must be a concrete id from availableTabs.\r\nThe session selects the manager and tenant; request bodies cannot select another account or grant Kids/operation permissions.\r\nActive credentials and an explicit whole-tenant KID grant are checked again inside the serializable Log7 transaction.\r\nNo Managers tab or Managers Write is required. You may remove any own tab and later restore it while the all-banks grant remains.\r\nPreserves unrelated/unknown numeric tab values; identical selections append no history. Returns the committed selection and revision.\r\n400 invalid-tab-change; 401 invalid/revoked session; 403 missing-tenant-access;\r\n409 tabs-conflict or invalid-stored-tabs: reread before a manual retry; 503 unavailable/uncertain storage: never retry automatically.\r\nPermissions are invalidated immediately on this instance; other instances refresh within 60 seconds. The portal refreshes workspace navigation after the confirmed save.",
        "operationId": "SetMyManagerTab",
        "parameters": [
          {
            "name": "tabId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalTabRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalTabRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalTabRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerTabs"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerTabs"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerTabs"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/profile/{field}": {
      "post": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Save one personal name, organisation, person icon, theme or deleted-record visibility preference.",
        "description": "### Request\r\n- field is the exact setting name: Name, Organisation, Icon, ThemeMode, RetentionDays or IconSet. Other settings are rejected.\r\n- Send value (string for display fields, integer 0–2 for ThemeMode) and revision from GetMyManagerProfile or the last successful write.\r\n- Name/Organisation allow up to 200 characters without controls. Icon must be in the person catalog; an existing legacy icon remains visible.\r\n- IconSet requires the exact JSON string \"g\" or \"line\". It selects artwork only, not the IconKid or any permissions. Missing/invalid stored values read as \"line\"; an explicit saved \"g\" is preserved.\r\n- RetentionDays requires a JSON integer from 0 to 2147483647. It controls visibility of otherwise authorized deleted records, not physical deletion. 0 hides deleted records; Tabs, Kids and operation permissions still apply.\r\n- Saves to your own Log7 history only. Administrative self-edit locks and grants are unchanged.\r\n### Response and errors\r\n- 200 returns the acknowledged profile and new revision. Repeating an identical stored value creates no history.\r\n- 400 invalid-profile; 401 stale/inactive session; 409 profile-conflict: reload before deciding whether to overwrite; 503 unavailable/uncertain storage.\r\n- Do not automatically retry an uncertain write. Cache invalidation is immediate on this instance; other instances refresh within 60 seconds.",
        "operationId": "SetMyManagerProfileField",
        "parameters": [
          {
            "name": "field",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalProfileRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalProfileRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalProfileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerProfile"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerProfile"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalManagerProfile"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/email-verification": {
      "post": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Send a verification link to your new email address.",
        "description": "### Verification\r\n- Send email, currentPassword and optional language en/da/es. The current password is required even for a local development session.\r\n- 202 email-verification-queued means the mail is queued, not delivered; the existing address stays unchanged.\r\n- The trusted portal link expires after 30 minutes. Confirm it explicitly using ConfirmMyManagerEmail; a GET never changes an account.\r\n- The link is bound to this tenant/environment and the current email, password and verification log revisions. Changing any of these invalidates it.\r\n### Temporary delivery policy and errors\r\n- Verification is currently available only for exact domains nortec.dk, kombinetech.com and arendt.dk.\r\n- 400 email-delivery-restricted for other domains: redirected development mail cannot prove ownership of the requested address. The central mail restriction is not bypassed.\r\n- Other 400 codes: invalid-email, current-password-invalid, email-already-verified. 401 invalid session; 429 rate-limited (two requests/15 minutes per account, plus IP limit); 503 unavailable.\r\n- Never log currentPassword, request bodies or verification tokens. No caller-provided redirect URL is accepted.",
        "operationId": "RequestMyManagerEmailVerification",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalEmailRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalEmailRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalEmailRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/session/me/email-confirmation": {
      "post": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Confirm the new mailbox with its single-use verification token.",
        "description": "### Confirmation\r\n- Anonymous POST accepting only token; possession authorizes only this exact verified address change. No manager or tenant selector.\r\n- 200 email-verified commits the email, a proof bound to its log version, and a notification to the former address together.\r\n- Old-address notifications follow the central development recipient policy. The new-address proof is never sent to a substitute mailbox.\r\n- Existing sessions keep their expiry and permissions. Sign in with the verified address next time. Password changes invalidate outstanding links.\r\n### Errors\r\n- 400 invalid-email-token for expired, used, wrong-site, stale or inactive-account proofs; 429 IP limit; 503 unavailable/uncertain storage.\r\n- Do not automatically retry an uncertain confirmation; read your profile or request a new link. No token or email is echoed.",
        "operationId": "ConfirmMyManagerEmail",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalEmailConfirmation"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalEmailConfirmation"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalEmailConfirmation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/session/me/password": {
      "post": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Change your password after reauthentication and repeated new-password entry.",
        "description": "### Password change\r\n- Send currentPassword, password, confirmPassword and optional language en/da/es. The current password is always checked against locked current data.\r\n- New passwords must match, differ from the old one, and contain 12–128 printable ASCII characters without leading/trailing spaces (shared legacy hash compatibility).\r\n- 200 password-changed commits password history and notification mail together. Discard the old token and sign in again.\r\n- Other API instances may cache old credentials for up to 60 seconds. The portal signs out after successful change.\r\n- Notification mail follows the existing development recipient policy. Never log these fields or automatically retry uncertain writes.\r\n### Errors\r\n- 400 invalid-password, current-password-invalid or password-unchanged; 401 stale/inactive session; 429 rate-limited (two attempts/15 minutes per account plus IP limit); 503 unavailable.",
        "operationId": "ChangeMyManagerPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalPasswordRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalPasswordRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PersonalPasswordRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonalAccountResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/services/export-count": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetServiceExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/services": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "List concrete service enum identities, including services without saved settings.",
        "description": "### Access\r\n- Requires an active manager, Services1 (60), PermissionService2 Read and a whole-tenant KID grant.\r\n- Write does not imply Read. Manager permissions alone do not grant service access.\r\n- The bounded session snapshot is at most 60 seconds old; every request rechecks tenant, state and credential stamp.\r\n### Catalog and storage\r\n- Reads Name and Icon from this site's A{TenantId:D4}.Log7, BankId=0, in one bounded query.\r\n- Every concrete eUserId in the service range is included, even without Log7 settings. Range-end markers are excluded.\r\n- Identity is eUserId.ToString(). KIDs use the existing Manager type and bank zero, with the service ID allowlist.\r\n- No API-key hashes are selected or returned. An absent/unsafe icon displays the server icon.\r\n### Filtering and errors\r\n- filter matches Identity or Name as a literal ordinal case-insensitive substring, maximum 128 characters.\r\n- sort is identity or name; direction is asc or desc. Name ties use numeric identity. The finite catalog is returned once; nextCursor is null.\r\n- 400 invalid-filter/invalid-sort; 401 revoked session; 403 missing-services-tab/read or missing-tenant-access.\r\n- 503 services-unavailable on database failure or the 12-second deadline. No partial result and no automatic retry.",
        "operationId": "GetServices",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDirectoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/services/count": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Count the predefined service identities without reading service settings.",
        "description": "Same active session, Services1, Service Read and whole-tenant scope as GetServices.\r\n            Uses the identical PortalServiceIds catalog (distinct concrete enum values, excluding range-end markers).\r\n            Independent of directory filtering. No service database read; the existing bounded session cache still\r\n            validates access. Returns count and the red-badge iconKid. 401/403 as GetServices; no-store.",
        "operationId": "GetServiceCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/services/{serviceKid}": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Read one predefined service, editable metadata and its icon catalog.",
        "description": "### Access and identity\r\n- Same active-manager, Services1, Service Read and tenant-wide grant as GetServices.\r\n- serviceKid must be a canonical bank-zero Manager KID for a concrete service enum value on this site.\r\n- A service exists by enum definition, including before its first settings write. No identity is allocated.\r\n### Editing metadata\r\n- CanEdit additionally requires Service Write. Only these callers receive ApiKeyHash; readers receive null and HasApiKeyHash.\r\n- ProfileRevision covers raw Name, Icon, ApiKeyHash and legacy Password, including row presence. It is not authorization.\r\n- AvailableIcons contains known eIcon names; a safe legacy current icon appears first for display only.\r\n- Hash values are opaque existing hashes, not plaintext keys. This operation does not implement service login.\r\n- Service accounts have no permission matrix, assigned KID scopes or tabs. No access object is returned.\r\n- Each business endpoint explicitly authorizes the authenticated eUserId; synchronization requires ServiceSync.\r\n- Stored access settings are preserved but ignored for service authorization. Account state, key and tenant checks remain.\r\n### Errors\r\n- 400 invalid-service-kid; 401/403 as GetServices; 503 services-unavailable. No-store, 12-second deadline.",
        "operationId": "GetService",
        "parameters": [
          {
            "name": "serviceKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetailsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetailsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetailsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/services/{serviceKid}/profile/{field}": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Save one service Name or Icon.",
        "description": "### Access and validation\r\n- Requires Services1, independent Service Read and Write, and a whole-tenant KID grant.\r\n- Rechecks the acting manager's current account, credential stamp, tab and scope inside the write transaction.\r\n- field is exactly Name or Icon. Value is a string. Name allows up to 200 non-control characters.\r\n- Icon must be a known selectable eIcon name. ApiKeyHash cannot be supplied or cleared manually:\r\n  field ApiKeyHash returns 400 invalid-service-profile, even with an empty value. Use GenerateServiceApiKey to replace the key.\r\n### Storage and acknowledgement\r\n- Appends one setting to this tenant's bank-zero Log7 history, with acting manager and database MS2000.\r\n- Serializable transaction; verifies the current Log7 trigger before commit. Unchanged values add no history.\r\n- Supply ExpectedRevision from GetService. Update UI only after the complete 200 response and use its new ProfileRevision.\r\n- No login, token issuance, permission grant, other service setting or Alive update is performed.\r\n### Errors\r\n- 400 invalid-service-kid/invalid-service-profile; 401/403 as GetServices, plus missing-services-write.\r\n- 409 service-profile-conflict: reload and review. 503 services-unavailable: outcome may be uncertain; reread before manual retry.\r\n- Do not retry writes automatically. No-store; request maximum 4096 bytes; 12-second deadline.",
        "operationId": "SetServiceProfileField",
        "parameters": [
          {
            "name": "serviceKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "field",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceProfileRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceProfileRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceProfileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetailsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetailsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetailsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/services/{serviceKid}/api-key": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Generate a service API key beginning with kt_ and save its password-compatible hash.",
        "description": "### Access and concurrency\r\n- Requires an active manager, Services1, independent Service Read and Write and a whole-tenant KID grant.\r\n- ExpectedRevision must match GetService. Authorization is repeated inside the same Log7 transaction as the save.\r\n### Key and storage\r\n- Generates kt_ followed by 64 cryptographically random ASCII letters and digits, always including both uppercase and lowercase letters. Total length is 67 characters. Keys are case-sensitive.\r\n- Uses exactly the existing manager password hashing function (HubManager.SHA512Salt compatible).\r\n- Only the resulting 128-character uppercase hash is stored as eSetting.ApiKeyHash, separately from Password. Replaces the previous hash.\r\n- The response keeps its existing apiKeyHash/hasApiKeyHash names; these describe ApiKeyHash; existing Password-only service keys remain readable until replaced.\r\n- The plaintext key appears only in this successful response, alongside the committed details and next revision.\r\n- GetService cannot recover it. Copy it before leaving the page; never log the key or response, or store it in browser storage.\r\n- Does not issue bearer tokens. This is the only operation for replacing the stored API-key hash; manual profile hash writes are rejected.\r\n### Errors\r\n- 400 invalid-service-kid/invalid-service-profile; 401 revoked session; 403 missing service tab/read/write or tenant access.\r\n- 409 service-profile-conflict: reread and review. 503 services-unavailable: the outcome can be uncertain; no key is returned.\r\n- Never retry automatically. Reread before generating again after a lost response; a new generation replaces the key.\r\n- No-store, 12-second deadline, maximum 4096-byte request. UI must not offer a key as saved before the complete 200 response.",
        "operationId": "GenerateServiceApiKey",
        "parameters": [
          {
            "name": "serviceKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceApiKeyRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceApiKeyRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceApiKeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceApiKeyResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceApiKeyResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceApiKeyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/settlements": {
      "get": {
        "tags": [
          "Settlements"
        ],
        "summary": "Lists 25 closed settlement periods, newest first, and the next scheduled settlement.",
        "description": "### Access\r\n            \r\n- Requires **Settlement2**, **Bank Read**, **User Read** and access to the **entire bank**.\r\n- Location-only access cannot expose bank-wide totals.\r\n            \r\n### Results and paging\r\n            \r\n- Returns **25 closed periods**, newest first, plus the next scheduled settlement.\r\n- Follow `nextBeforePeriod` to read older periods. Unknown metadata is null.\r\n- `amountMinor` is the signed stored sum, not a recalculated export total or a major-unit currency amount.\r\n            \r\n### Cache and effects\r\n            \r\n- Metadata is cached for at most **60 seconds**.\r\n- No writes, settlement jobs or notifications are performed.",
        "operationId": "GetBankSettlements",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "beforePeriod",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SettlementHistoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettlementHistoryResponse"
                },
                "example": {
                  "kid": "3E7Q14o2Ab",
                  "nextSettlement": null,
                  "periods": [
                    {
                      "period": 12,
                      "settlementDate": "2026-09-01T00:00:00Z",
                      "settlementRun": "2026-09-01T02:00:00Z",
                      "firstTransaction": null,
                      "lastTransaction": null,
                      "amountMinor": -12500,
                      "transactionCount": 45
                    }
                  ],
                  "nextBeforePeriod": null
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettlementHistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/settlements/{period}": {
      "get": {
        "tags": [
          "Settlements"
        ],
        "summary": "Reads grouped totals for one period (zero is the provisional current period) and lists available export formats.",
        "description": "### Access and amounts\r\n            \r\n- Uses the same **full-bank permissions** as `GetBankSettlements`.\r\n- Returns grouped totals and available export formats. **Currency groups are never merged.**\r\n- Uses current user metadata.\r\n            \r\n### Provisional data and cache\r\n            \r\n- Period **0** is the provisional current period and may change before settlement.\r\n- Settlement is exempt from **RetentionDays**.\r\n- Source data is cached for at most **one minute**.",
        "operationId": "GetBankSettlementPeriod",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SettlementDetailResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettlementDetailResponse"
                },
                "example": {
                  "kid": "3E7Q14o2Ab",
                  "period": 12,
                  "sourceEntries": 45,
                  "includedEntries": 42,
                  "groups": [
                    {
                      "group": "LR",
                      "currency": "DKK",
                      "entries": 42,
                      "amountMinor": -12500
                    }
                  ],
                  "formats": [
                    "XLS",
                    "NAVISION"
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettlementDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/tenant/status": {
      "get": {
        "tags": [
          "TenantStatus"
        ],
        "summary": "List Offline and AutoOutOfOrder alerts, newest first, using parallel lookups.",
        "description": "Requires an active manager, TenantStatus1 (80), Bank Read, Location Read, Unit Read and matching\r\nsite/bank/location KID grants. Each request checks the bounded manager snapshot (at most 60 seconds old).\r\nNo tenant selector is accepted. Grants and RetentionDays for bank/location/unit are applied before LIMIT.\r\nLocations require Enabled exactly 1. Missing Deleted means zero; malformed/future deletions are hidden.\r\nOffline reads the site's Alive rows with UnitId=MainId, excluding Cluster Test, using last server contact:\r\nCash at least one hour old; other nonempty BankType at least one day old; at most 100 days old, inclusive.\r\nAutoOutOfOrder reads Log24 OutOfOrder with value AutoOutOfOrder; excludes StartSMS_60 and TimeSMS_61.\r\nOnly original packed UnitType determines type via (value shifted right 1) AND 255. UnitType2 is ignored, including as a fallback.\r\nUnknown/missing types are excluded from AutoOutOfOrder. ErrorId is the positive integer Id in the state JSON.\r\nNames resolve localization placeholders using Accept-Language. All identities are canonical KIDs.\r\nbankIconKid and locationIconKid are ready-to-render bank/location icons from Log24;\r\nmissing/invalid settings use bank_building/house. The API adds the object number to Kid.Text.\r\nTimestampUtc means last contact for Offline and the OutOfOrder setting timestamp for AutoOutOfOrder.\r\nlimit is per source, 1–1000 (default 200). Sources hasMore explicitly reports truncation; there is no cursor.\r\nItems sort by timestamp descending, then kind and KID. The same unit may appear for both kinds.\r\nSources run concurrently on separate connections within a 12-second request deadline. A failed lookup\r\nhas errorCode=status-source-unavailable and no items; successful sources remain available in HTTP 200.\r\nIf all lookups fail, HTTP 503 tenant-status-unavailable is returned. Never interpret a partial result as healthy.\r\nClients must tolerate additional source kinds. Refresh after 30 seconds; no overlapping or hidden-page polling.\r\n400 invalid-limit; 401 invalid/revoked session; 403 missing-status-tab, missing-bank-read,\r\nmissing-location-read, missing-unit-read or missing-resource-access. Responses are no-store.",
        "operationId": "GetTenantStatus",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/TenantStatusResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantStatusResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantStatusResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/tenant/status/page": {
      "get": {
        "tags": [
          "TenantStatus"
        ],
        "summary": "Read 25 status rows at a time with next/previous cursors.",
        "description": "Same authorization, visibility and source failures as GetTenantStatus. pageSize is 1–100 (default 25).\r\nWithout cursor, reads a fresh bounded snapshot (1,000 rows per source). Sources counts describe that snapshot,\r\nnot just the page; hasMore still reports source truncation. Status.items contains only this page.\r\nCopy previousCursor/nextCursor unchanged with the same pageSize and language. Snapshots last at most two minutes\r\nand may be evicted earlier. Every page rechecks credentials, Tab, operations, resource scope and RetentionDays.\r\nCursors are manager/site/scope/language bound and never grant access. HTTP is no-store.\r\nFor a 30-second refresh omit cursor. Optional offset (0–1999) and anchor (Kind:Kid, at most 300 characters)\r\npreserve the visible position: the anchor is matched only among authorized results; otherwise offset is clamped.\r\nDo not combine cursor with offset/anchor. 400 invalid paging input/cursor, 409 changed cursor context,\r\n410 expired/evicted snapshot: restart without cursor. 401/403/503 retain GetTenantStatus meanings.",
        "operationId": "GetTenantStatusPage",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0
            }
          },
          {
            "name": "anchor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/TenantStatusPageResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantStatusPageResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantStatusPageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "410": {
            "description": "Gone",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/tenant/tools/time": {
      "post": {
        "tags": [
          "Tools"
        ],
        "summary": "Convert MS2000, MI2000, SS2000, UTC or a local wall time without floating-point integers.",
        "description": "Requires active manager, More1, Bank Read and at least one resource grant in the trusted site's tenant.\r\n            No bank or tenant selector is accepted. Bank/location-restricted managers can use these pure calculators.\r\n            No business data is read or changed. TimeZone is an explicit browser IANA zone, never server-local.\r\n            Formats are ms2000, mi2000, ss2000, utc, local. Integers are decimal strings. Date input follows\r\n            Kombine.Flex.Time's 2 ms quantization; numeric MS2000 preserves each millisecond. UTC requires Z/offset.\r\n            DST gaps fail; overlaps return both OffsetChoices and require explicit Offset on resubmission.\r\n            Unsupported MI2000/SS2000 ranges return null instead of the library's wraparound. See the tools guide.",
        "operationId": "ConvertToolTime",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolTimeRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolTimeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ToolTimeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTimeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTimeResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTimeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTimeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTimeResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTimeResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/tenant/tools/kid": {
      "post": {
        "tags": [
          "Tools"
        ],
        "summary": "Inspect only the supplied KID with the installed Kombine.Flex.Kid parser.",
        "description": "Same tenant-bound More1/Bank Read/scope requirements as ConvertToolTime. This is a syntax inspector:\r\n            it never resolves names, verifies existence or grants access to an inspected identity.\r\n            Nonzero, nondefault data properties are returned as strings. Enum names/numbers and list indexes\r\n            are separate fields. Normalized indicates parser normalization; CanonicalKid is its serialization.\r\n            Controls, input over 2048 characters and input with no usable content return 400 invalid-tool-kid.",
        "operationId": "InspectToolKid",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolKidInspectionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolKidInspectionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ToolKidInspectionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ToolKidInspectionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolKidInspectionResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolKidInspectionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/{unitKid}/documents": {
      "get": {
        "tags": [
          "UnitDocumentList"
        ],
        "summary": "List document identities produced by the selected Unit for WashDoc3.",
        "description": "### Access\r\nActive manager bearer session, WashDoc3 (55), Location Read, Unit Read and a matching tenant/bank/location grant.\r\nThe canonical unit KID must belong to the trusted site tenant. Location and unit visibility follow RetentionDays before history paging.\r\n### Time and ordering\r\ndate is a UTC calendar date (yyyy-MM-dd), defaulting to today. Includes that entire date and earlier history back to 2000-01-01.\r\nMatches tagged Cycle settings for exactly this unit. lastActivityUtc is the latest matching Cycle timestamp inside the interval,\r\nnot the document start/end. Open GetUnitDocumentTable to read its full interval and measurements.\r\nsort=activity (default) or documentId, direction=asc or desc (default). Document IDs sort numerically.\r\nStable identity breaks activity ties. limit 1–100 (default 25), offset 0–100000; hasMore indicates another page.\r\nLive changes can shift offset pages; reset offset when changing filters or refreshing. No total count or measurement reads.\r\n### Errors and limits\r\n400 invalid KID/time/sort/page; 401 inactive/expired session; 403 missing access; 404 hidden/missing location or unit;\r\n422 oversized metadata; 503 storage unavailable/busy. Twelve-second storage deadline; no response cache.\r\nImplemented locally, unreleased. Generated client and download package updates are deferred to beta preparation.",
        "operationId": "GetUnitDocuments",
        "parameters": [
          {
            "name": "unitKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Sort",
            "in": "query",
            "description": "activity (default) or documentId. Document IDs sort numerically.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Direction",
            "in": "query",
            "description": "asc or desc (default).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Offset",
            "in": "query",
            "description": "Zero-based offset, up to 100000.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Limit",
            "in": "query",
            "description": "Page size, 1–100; defaults to 25.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "description": "Optional exact numeric Doc ID or canonical document KID belonging to the selected unit. Applies within the selected date cutoff.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Date",
            "in": "query",
            "description": "UTC calendar date (yyyy-MM-dd), inclusive through its last millisecond; defaults to UTC today.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentPage"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentPage"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/{unitKid}/documents/count": {
      "get": {
        "tags": [
          "UnitDocumentList"
        ],
        "summary": "Count distinct WashDoc3 document identities for exactly one unit, separately from list loading.",
        "description": "Uses the same active manager, WashDoc3, Location/Unit Read, tenant, resource scope and RetentionDays checks as GetUnitDocuments.\r\ndate is a UTC calendar date (yyyy-MM-dd), defaulting to today; includes that entire date and all earlier history since 2000-01-01.\r\nCounts distinct document IDs from tagged Cycle settings only, without paging through results or reading measurements.\r\nReturns count and the effective inclusive UTC from/through bounds. Concurrent data changes may change the total between requests.\r\n400 invalid KID/date; 401 inactive/expired session; 403 missing access; 404 hidden/missing location or unit;\r\n422 oversized metadata; 503 storage unavailable/busy. Twelve-second storage deadline; no response cache.",
        "operationId": "GetUnitDocumentsCount",
        "parameters": [
          {
            "name": "unitKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "description": "Optional exact numeric Doc ID or canonical document KID belonging to the selected unit. Applies within the selected date cutoff.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Date",
            "in": "query",
            "description": "UTC calendar date (yyyy-MM-dd), inclusive through its last millisecond; defaults to UTC today.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDocumentCount"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/neighbors": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Find the previous (higher Doc ID) and next (lower Doc ID) existing document for this exact unit.",
        "description": "Requires the same active manager, WashDoc1/2/3 tab, Location/Unit Read, tenant, resource scope and RetentionDays checks as GetUnitDocumentTable.\r\nReturns nullable previous/next objects with a canonical document kid and lastActivityUtc (latest tagged Cycle timestamp).\r\nDoc IDs count down: previous is the nearest higher numeric ID (older document), next the nearest lower ID (newer document).\r\nSkips gaps in document numbers. Searches the unit's full stored history independently of list dates, sort and filters.\r\nA missing neighbor is null; a missing selected document is 404. No measurements, other units or settings are exposed.\r\nUncached. 400 invalid document KID; 401 expired credentials; 403 missing permission; 404 hidden/missing location, unit or document;\r\n503 unavailable/busy storage. The twelve-second storage deadline applies. Implemented locally, unreleased.",
        "operationId": "GetUnitDocumentNeighbors",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentNeighbors"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentNeighbors"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentNeighbors"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/table": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Read a document's table as JSON with original values and column metadata.",
        "description": "### Access\r\n- Active manager bearer session; at least one of WashDoc1 (54), WashDoc3 (55), WashDoc2 (75); Location Read and Unit Read.\r\n- Requires a tenant/bank/location grant matching the canonical document KID. The site's tenant is fixed.\r\n- Location and unit deletion follow RetentionDays, including on SVG cache hits.\r\n### Fields and values\r\n- Optional `states`/`settings`: comma-separated exact enum names declared for this unit type. Omit for all permitted fields; an empty value selects none.\r\n- Optional `historicalMeasurements=true` adds the fixed document-only measurement/event profile for older machine histories, independently of today's model. Default false; graph2 enables it automatically. It never adds settings or credential access.\r\n- Hidden, credential, unbound and other-object fields are never read. Unknown types return 422. Invalid/unavailable fields return 400.\r\n- Rows use exact MS2000 timestamps, with cells indexed by column position. Null cell means absent; a cell with null text/value is a stored null.\r\n- A selected column is omitted when every cell in the complete document has no numeric value and null, empty or whitespace-only text. Zero and false are data. Build column mappings from each response; rows and timestamps are preserved, even when no columns remain. Downloads use the same selection.\r\n- `text` preserves the decoded original; `value` is a finite double when possible. No interpolation or rounding. Use text for exact large numbers.\r\n- `finished` requires a terminal Cycle and an InSync timestamp at least two minutes beyond the document end.\r\n### Limits and errors\r\n- One document, at most 31 days, 128 columns, 50,000 source samples and 500,000 cells. A 12-second storage deadline applies.\r\n- 400 invalid KID/selection; 401 inactive/expired session; 403 missing access; 404 missing/hidden object or document; 422 unsupported type/oversized document; 503 storage unavailable.\r\n- Tables and downloads are uncached. Original enum identifiers and UTC timestamps are language independent.",
        "operationId": "GetUnitDocumentTable",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTable"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTable"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTable"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/table.html": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "View a document as a printable HTML table.",
        "description": "### Access and data\r\nSame KID, authorization, field selection and bounds as GetUnitDocumentTable. Requires a manager bearer token.\r\n### Output\r\nStandalone HTML with UTC timestamps, original text, fixed English labels and no scripts or external resources. No interpolation. Browser caching is disabled.",
        "operationId": "GetUnitDocumentHtml",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/graph.svg": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Render a document's numeric series as an SVG chart, caching completed documents privately.",
        "description": "### Access\r\nSame authorization as GetUnitDocumentTable, reapplied before every cache lookup. Download with bearer authentication; this is not a public image URL.\r\n### Graph\r\nSame field selection; at most 16 numeric series, one labelled scale per series. Width is 480–2400 pixels (default 1200).\r\nThe SVG uses UTC timestamps, native lines and steps for enums/booleans, with no scripts, external resources or third-party SVG renderer.\r\nMissing stored values break a line; sparse timestamps for other series do not. No fabricated samples or smoothing. 422 means no numeric data or too many series; select fewer fields.\r\n### Cache\r\nOnly finished=true results enter the private disk cache, for at most 24 hours. In-progress data is read/rendered again.\r\nKeys include tenant-bound document KID, unit type/name, exact ordered field selection, width and renderer version.\r\nServer cache is bounded to 128 MiB/256 files. Cache I/O failure still permits uncached rendering. HTTP responses always use no-store so revoked access cannot be bypassed by browser/CDN caches.",
        "operationId": "GetUnitDocumentSvg",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "width",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/graph2.svg": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Render a responsive WashDoc chart with independent text and graph layers.",
        "description": "Same authorization as GetUnitDocumentTable, checked before every private cache lookup. Enables the fixed historicalMeasurements profile.\r\nDoc ID selects the tagged Cycle history; PREPARING/DONE and last tagged measurements resolve the legacy cycle window.\r\nThe graph adds one minute of margin, rounds duration up to the next minute, and reads bounded nearest edge samples\r\nfor observed measurement fields (at most one hour outside that graph window). Old untagged measurements remain supported.\r\nContext samples anchor clipped curves; they do not extend the visible time axis. No smoothing or fabricated measurements.\r\nTemperature, level and spin use separate bands with matching target overlays; stored Cycle/Process/CycleSub/Error events are marked.\r\nAt most 16 numeric series. Empty/non-numeric selections return 422. Times are UTC.\r\nSVG fills its viewport in both directions while text size and stroke thickness remain stable; no script or third-party renderer.\r\nThe original GetUnitDocumentSvg remains available. Finished results use a separate bounded private cache, with no-store HTTP responses.",
        "operationId": "GetUnitDocumentSvg2",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/graph": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Read semantic WashDoc graph JSON for interactive charts and image rendering.",
        "description": "Same active-manager, WashDoc tab, Location/Unit Read, tenant, scope and retention checks as GetUnitDocumentTable.\r\nUses the graph2 data path: exact document cycle boundaries, one-minute graph margin/rounding and bounded edge context.\r\nSparse measurement and target points retain exact MS2000 timestamps, stored nulls, calculated/edge flags and known units.\r\nNo smoothing, resampling, coordinate transforms or inferred quantities. Level is not assumed to be liters.\r\nPresentation contains the trusted original UnitType, family and preferred group order. Observed extra measurement groups remain available.\r\nAlliance dryers (19/29/30) interpret legacy Level as Temperature2; their flags expose heat (32|64), airflow (16), and null water inlet/outlet.\r\nOther InOutletHeat flags expose heat (32), inlet (1|2|4|8), outlet (16); unknown remains null. SoapInfo keeps actual recorded dosing.\r\nQW washer types 15/16/17/25/31 record bare Spin as ordinal levels, with no rpm unit. Explicit rotation-scale JSON retains its units.\r\nCycle/Process/CycleSub/Error events retain enum codes and localized labels where shared enum translations exist.\r\nLegacy Process (state 138) retains eProcess byte codes: 1 Prewash, 2 Mainwash, 3/4/5 rinses, 6 Spin, 7 Done.\r\nIts labels reuse equivalent shared phase translations; Process codes never become CycleSub codes or document boundaries.\r\nOriginal enum names and timestamps are language independent. Clients must not treat edge/calculated points as actual hover samples.\r\nMaximum 16 numeric series; 31 days, 50,000 samples, 500,000 cells and the existing 12-second storage deadline apply.\r\nReturns 400 invalid KID/fields, 401 expired credentials, 403 missing permission, 404 hidden/missing,\r\n422 unsupported type/oversized or empty graph, and 503 unavailable storage. Uncached; every request reauthorizes.",
        "operationId": "GetUnitDocumentGraph",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/WashDocChartResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WashDocChartResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/WashDocChartResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/graph.png": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Render a document KID as a PNG image with the shared local Chart.js renderer.",
        "description": "Same authorization, fields, unit-type presentation, semantic data, exact timestamps and bounded graph context as GetUnitDocumentGraph.\r\nNo client chart configuration or open browser is needed. The server renders a 1600×1000 opaque PNG locally;\r\nmeasurements are never sent to an external chart service. This full graph requires manager bearer authentication.\r\nEvery request reauthorizes and returns no-store. A bounded unavailable/failed renderer returns\r\n503 document-renderer-unavailable; storage and validation errors match GetUnitDocumentGraph.",
        "operationId": "GetUnitDocumentPng",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "image/png": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "image/png": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "image/png": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "image/png": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "image/png": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "image/png": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/documents/{documentKid}/icon.svg": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Render a text-free visual WashDoc preview for document lists and icon grids.",
        "description": "Uses the same authorized historical measurements, cycle window and private graph artifact as GetUnitDocumentSvg2.\r\nCurves are reduced while preserving local peaks. No axes, labels, target overlays or quantitative reading scale.\r\nAccess and visibility are checked before every cache lookup. Finished artifacts share the graph cache; responses use no-store.\r\nEmpty/non-numeric measurements return 422. Clients should load visible previews lazily with bounded concurrency.",
        "operationId": "GetUnitDocumentIcon",
        "parameters": [
          {
            "name": "documentKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "States",
            "in": "query",
            "description": "Exact comma-separated eState names; omit for permitted states or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Settings",
            "in": "query",
            "description": "Exact comma-separated eSetting names; omit for permitted settings or empty for none.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "HistoricalMeasurements",
            "in": "query",
            "description": "Also permit the fixed historical WashDoc measurement/event fields, independently of today's unit model. Default false; graph2 always enables this.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Content",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/export-count": {
      "get": {
        "tags": [
          "UnitsDirectory"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetUnitExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "terminalKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "runningOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "autoOutOfOrderOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/terminals/export-count": {
      "get": {
        "tags": [
          "UnitsDirectory"
        ],
        "summary": "Count authorized main terminals matching the export filters.",
        "operationId": "GetTerminalExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "terminalKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "runningOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/active-count": {
      "get": {
        "tags": [
          "UnitsDirectory"
        ],
        "summary": "Count accessible active units for the Units1 navigation icon.",
        "description": "Requires an active manager, Units1 (50), Bank/Location/Unit Read and current site/bank/location grants.\r\nCounts distinct Log24 units (BankId at least 1000) with Enabled exactly 1 and Deleted zero;\r\nmissing Deleted means zero, missing/invalid Enabled or malformed Deleted are excluded, including for site-wide grants.\r\nLimited grants also require an enabled parent location and Bank/Location deletion visible under RetentionDays.\r\nNo search, paging or client-selected scope is accepted. Returns count and iconKid containing Kid.Count.\r\nThe aggregate is read afresh; permission snapshots live at most 60 seconds. No request can select another tenant.\r\n401 invalid/revoked session; 403 missing-units-tab, missing-bank-read, missing-location-read,\r\nmissing-unit-read or missing-resource-access; 503 units-unavailable (storage unavailable or 12-second deadline).\r\nRetry unavailable requests manually. No-store.",
        "operationId": "GetActiveUnitCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveUnitCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveUnitCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveUnitCountResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/terminals/active-count": {
      "get": {
        "tags": [
          "UnitsDirectory"
        ],
        "summary": "Count accessible active terminals for the Terminals1 navigation icon.",
        "description": "Requires an active manager, Terminals1 (66), Bank/Location/Unit Read and current site/bank/location grants;\r\nUnits1 is not required. Uses the same active-only state and parent visibility rules as GetActiveUnitCount.\r\nOnly Log24 units whose ID appears as a positive MainId in the tenant-bound Alive table at the same bank and\r\nlocation qualify. Repeated Alive references count once; orphan Alive identities never count. Read-only classification.\r\nNo search, paging or client-selected scope is accepted. Returns count and iconKid containing Kid.Count.\r\nThe aggregate is read afresh; permission snapshots live at most 60 seconds. No request can select another tenant.\r\n401 invalid/revoked session; 403 missing-terminals-tab, missing-bank-read, missing-location-read,\r\nmissing-unit-read or missing-resource-access; 503 terminals-unavailable (storage unavailable or 12-second deadline).\r\nRetry unavailable requests manually. No-store.",
        "operationId": "GetActiveTerminalCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveUnitCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveUnitCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveUnitCountResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units": {
      "get": {
        "tags": [
          "UnitsDirectory"
        ],
        "summary": "List authorized units, including child units, for Units1.",
        "description": "Requires Units1 (50), Bank/Location/Unit Read and current resource grants. Every page rechecks the active manager.\r\nReads tenant Log24, BankId >=1000, with optional bounded Alive.MainId terminal hierarchy. Limited grants require an enabled location and bank/location/unit deletion\r\nwithin RetentionDays; missing Deleted means zero, malformed/future values are hidden. Site-wide grants can inspect all states.\r\nenabledOnly=true requires unit Enabled exactly 1. No request can select another tenant.\r\npageSize 1–250 (default 50); filter max 128 characters searches stored names, unit number/type, WashDocId and OutOfOrder,\r\nor an exact site-relative/canonical bank, location or unit KID. Names use stored text for SQL search/order and localized display.\r\nsort: kid, name, bankName, locationName, unitId, unitType, washDocId, outOfOrder, errorUnit, progress; direction asc/desc.\r\nkid sorts numerically by bank, location and unit within the trusted tenant. Unit numbers/types/WashDocId sort numerically, others by MySQL utf8mb4_general_ci; bank/location/unit numbers break ties.\r\nfields: bankName, locationName, unitType, washDocId, outOfOrder, errorUnit, progress. Core parent names/icons remain populated.\r\nerrorUnit is the last stored eState.ErrorUnit JSON text (empty if absent, null unless selected); it does not prove the fault is still active. Sorting is lexical by stored text.\r\nprogress is optional and sortable with sort=progress (Units1 only), and uses the overview-card calculation at request time: status, percent, remainingSeconds, calculatedAtUtc.\r\nPercent uses only (now-start)/(expectedEnd-start)*100, clamped to 0–100; missing/invalid timing gives null.\r\nautoOutOfOrderOnly=true includes only Log24 eState.AutoOutOfOrder JSON with positive integer Id, independently of the OutOfOrder setting. Returns autoOutOfOrder JSON for those rows; otherwise null. Repeat the filter with cursors.\r\nrunningOnly=true requires valid positive Started/Done timestamps with Started <= calculation time < Done.\r\nFiltering precedes sorting/paging and does not require fields=progress. Default false; GetTerminals rejects true.\r\nCalculation time is fixed across the cursor chain (at most 15 minutes); refresh to reevaluate running units.\r\nRepeat runningOnly unchanged with each cursor. Authorization and retention use the current time.\r\nOptional unit fields are null unless selected, empty if missing. Only original packed UnitType determines type via (value shifted right 1) AND 255; UnitType2 is ignored, including as a fallback.\r\nterminal is optional {kid,name,iconKid}; the same-location Log24 main unit must be authorized and retention-visible. A child Alive.MainId may identify it when its own Alive row is absent; an existing contradictory main mapping is rejected. Unknown, chained or unavailable hierarchy returns null without discarding the page. Offline is independent.\r\nincludeCoordinates=true adds parent-location coordinates in decimal degrees, null if absent/invalid, for map presentation.\r\nFollow nextCursor until null. Protected cursors expire after 15 minutes and bind manager, tenant, grants, retention and all query options.\r\nRestart paging after changing options. Concurrent edits may move rows; pages are not a frozen snapshot.\r\nterminalKid on GetUnits is a canonical Controller KID (MainId); results include its first unit and child units mapped by same-location Alive.MainId.\r\nThe first unit remains a separate child. The parent must be a retention-visible Log24 unit with no contradictory parent mapping.\r\nA missing parent Alive row is allowed; missing child mappings never infer membership. GetTerminals rejects terminalKid.\r\nInvalid/wrong-tenant terminal KIDs return 400 invalid-terminal. Repeat terminalKid unchanged with each cursor.\r\nOptional locationKid is a canonical location KID in this tenant, intersecting grants before search/sorting/paging.\r\nRepeat it unchanged with cursors. Invalid/wrong-tenant KIDs return 400 invalid-location; it never grants access.\r\n400 invalid-page/filter/sort/fields/cursor; 401 invalid/revoked session; 403 missing-units-tab, missing-bank-read,\r\nmissing-location-read, missing-unit-read or missing-resource-access; 503 units-unavailable (retry manually). No-store.",
        "operationId": "GetUnits",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeCoordinates",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "terminalKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "runningOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "autoOutOfOrderOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDirectoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/terminals": {
      "get": {
        "tags": [
          "UnitsDirectory"
        ],
        "summary": "List authorized main units for Terminals1.",
        "description": "Requires Terminals1 (66), Bank/Location/Unit Read and current site-bound resource grants; Units1 is not required.\r\nEach row's iconKid is the fixed terminal icon, independent of eSetting.Icon, with UnitId in its Text field.\r\nUses the same Log24 unit directory, visibility and RetentionDays as GetUnits. Name is eState.ComputerName, without fallback to eSetting.Name.\r\nTerminal fields/sorts: versionMinor, bootReason, booted, firmware, storageCardSerialNumber, page, backLight.\r\nBooted comes from eSetting.Booted; other terminal columns come from eState. Values are decoded text, null unless selected.\r\nOnly units whose ID appears as a positive MainId in this tenant's Alive table for the same bank and location qualify.\r\nRepeated Alive references produce one unit; Alive identities absent from Log24 are omitted. This is a read-only classification.\r\npageSize 1–250 (default 50); filter max 128 characters searches stored names, unit number/type, WashDocId and OutOfOrder,\r\nor an exact same-site bank/location/unit KID. enabledOnly=true requires unit Enabled exactly 1.\r\nsort: kid, name, bankName, locationName, unitId, unitType, washDocId, outOfOrder; direction asc/desc.\r\nfields: bankName, locationName, unitType, washDocId, outOfOrder. Optional unit fields are null unless selected.\r\nincludeCoordinates=true returns parent-location coordinates for the map, null when absent/invalid.\r\nFollow nextCursor until null; cursors expire after 15 minutes and bind this directory, manager, tenant, grants,\r\nretention and all query options. Main-unit filtering precedes paging. Concurrent changes may move rows.\r\nterminalKid on GetUnits is a canonical Controller KID (MainId); results include its first unit and child units mapped by same-location Alive.MainId.\r\nThe first unit remains a separate child. The parent must be a retention-visible Log24 unit with no contradictory parent mapping.\r\nA missing parent Alive row is allowed; missing child mappings never infer membership. GetTerminals rejects terminalKid.\r\nInvalid/wrong-tenant terminal KIDs return 400 invalid-terminal. Repeat terminalKid unchanged with each cursor.\r\nOptional locationKid is a canonical location KID in this tenant, intersecting grants before search/sorting/paging.\r\nRepeat it unchanged with cursors. Invalid/wrong-tenant KIDs return 400 invalid-location; it never grants access.\r\n400 invalid-page/filter/sort/fields/cursor; 401 invalid/revoked session; 403 missing-terminals-tab, missing-bank-read,\r\nmissing-location-read, missing-unit-read or missing-resource-access; 503 terminals-unavailable (retry manually). No-store.",
        "operationId": "GetTerminals",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "name"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "fields",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeCoordinates",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "locationKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "terminalKid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "runningOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDirectoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/units/{unitKid}/groups/settings/{group}/{setting}": {
      "post": {
        "tags": [
          "UnitSettings"
        ],
        "summary": "Save one editable current-unit setting with revision protection.",
        "description": "### Access\r\n- Requires an active manager, an assigned Tab, matching location grant, Location Read, Unit Read and Unit Write.\r\n- Account, credential, permissions, retention and effective unit type are rechecked under database locks before writing.\r\n- Only fields declared in this type's setting group can be written. States, hidden, device-owned, read-only, ORM-managed, credential, MainUnit/other-scope and dynamic-option fields cannot be edited here.\r\n### Request and result\r\n- Send `value` as invariant text (maximum 4096 characters) and `expectedRevision` from GetUnitGroup for this field.\r\n- Price editors send raw minor units: displayed 12.50 becomes value \"1250\". RegExs.Price validates this raw value, not the displayed amount. Responses remain raw; decimal display text is invalid input.\r\n- Example: `{ \"value\": \"Washer 1\", \"expectedRevision\": \"64 hexadecimal characters\" }` for the Name setting.\r\n- Enum metadata and SettingsAndStates.json required/type/range/pattern/select constraints apply. Boolean values become 0/1. Empty optional values remain empty; no defaults are inserted.\r\n- Appends bank Log2 history with the editor's UserId and Sync=0. The Log24 projection must match before commit.\r\n- Returns confirmed value, source MS2000 and new revision. A successful save means storage accepted it, not that the physical unit has acknowledged it.\r\n### Errors\r\n- 400 invalid input; 401 session changed; 403 insufficient rights/read-only field; 404 invisible unit/location/group; 409 value/type changed; 503 storage failure.\r\n- On 409 reload before editing again. Never automatically replay after a timeout or lost response: a commit may have succeeded. Read back first.",
        "operationId": "SetUnitSetting",
        "parameters": [
          {
            "name": "unitKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "setting",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnitSettingRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UnitSettingRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UnitSettingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UnitSettingResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitSettingResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitSettingResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/balances": {
      "post": {
        "tags": [
          "UserBalances"
        ],
        "summary": "Read current and previous-period balances for up to 50 residents in one bank.",
        "description": "**Read-only POST** returning current and previous-period balances in one batch.\r\n            \r\n### Access and request\r\n            \r\n- Requires an active site-bound manager, Users2, User Read and a bank-wide resource grant.\r\n- Location-only grants cannot expose whole-bank balances.\r\n- Send canonical user KIDs, not numeric IDs or readable aliases.\r\n            \r\n### Balance calculation\r\n            \r\n- **Current:** Log1 period zero, the resident discount and FlexOrm's missing-settlement correction for non-cash banks.\r\n- **Previous:** the resident's highest positive period, which is not necessarily the bank's latest period. Period zero is never used as the previous period.\r\n- Both balances reuse one grouped ledger read. An existing resident without transactions still has their discount applied.\r\n            \r\n**Delayed settlement** produces a provisional previous period with a capped discount. This also applies to cash banks, whose current balance remains unchanged.\r\nThe provisional number is the bank's highest Log1 period plus one. It is an estimate, not a stored/settled period or a settlement download identifier.\r\n            \r\n### Currency\r\n            \r\n- Prefer the `balances` array: normalized Log1 currencies stay separate, without conversion. A null currency remains separate too.\r\n- The resident discount applies only to **DKK**. All currencies use the same resident previous period.\r\n- An absent currency in an existing previous period has a zero balance; no previous period remains null.\r\n- Scalar fields preserve the legacy cross-currency calculation for compatibility. Do not sum different currencies or use balances as a payment instruction.\r\n            \r\n### Posting and subscription metadata\r\n            \r\n- `latestPostingMs2000` is the latest Log1 posting across all periods and entry types, in UTC milliseconds since 2000-01-01; zero means no postings.\r\n- `hasActiveSubscription` reports an active card/SEPA subscription, not payment success or a collection instruction.\r\n- Both fields are null for missing/hidden residents and use the same authorized database snapshot as the balances.\r\n            \r\n### Missing data\r\n            \r\n- Missing or retention-hidden residents return `not-found` and null balances, never a fabricated zero.\r\n- No previous period: `previousBalanceMinor` and `previousPeriod` are null; `previousPeriodIsProvisional` is false.\r\n            \r\n### Limits and errors\r\n            \r\n- At most **two concurrent batches** per API process.\r\n- **20-second** database deadline; correction history is capped at **50,000 lines**.\r\n- Timeout or oversized correction: the entire request fails with **HTTP 503**. Reduce the batch instead of displaying partial balances.\r\n- For a lazy resident list, render the rows first, then request at most 10 residents per batch, one batch at a time.\r\n  The API maximum remains 50. Do not block list rendering or sum different currencies.\r\n- No database writes or shared balance cache.",
        "operationId": "GetBankUserBalances",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserBalancesRequest"
              },
              "example": {
                "userKids": [
                  "A6Q3Co7D0b44Ch"
                ]
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UserBalancesRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UserBalancesRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserBalancesResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserBalancesResponse"
                },
                "example": {
                  "items": [
                    {
                      "kid": "A6Q3Co7D0b44Ch",
                      "status": "ok",
                      "currentBalanceMinor": -12345,
                      "previousBalanceMinor": -25000,
                      "previousPeriod": 23,
                      "previousPeriodIsProvisional": false,
                      "balances": [
                        {
                          "currency": "DKK",
                          "currentBalanceMinor": -10000,
                          "previousBalanceMinor": -20000,
                          "previousPeriod": 23,
                          "previousPeriodIsProvisional": false
                        },
                        {
                          "currency": "EUR",
                          "currentBalanceMinor": -2345,
                          "previousBalanceMinor": -5000,
                          "previousPeriod": 23,
                          "previousPeriodIsProvisional": false
                        }
                      ]
                    }
                  ]
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserBalancesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "413": {
            "description": "Content Too Large",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "status": 503,
                  "code": "storage-timeout",
                  "title": "storage-timeout"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/next-number": {
      "get": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Suggest the next resident number from the bank's first NumberFormats entry and stored NumberFormatUserIndex (default 1).",
        "description": "Requires an active manager, Users2, User Read and Create, and bank-wide scope. Uses FlexOrm conversion, testing up to nine candidates and skipping occupied active numbers. Empty number means no suggestion. Read-only: no reservation or index update. Creation revalidates availability. Errors: 400 invalid bank, 401 session, 403 permission, 503 invalid stored format or unavailable storage.",
        "operationId": "GetBankUserNumberForNewUser",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserNumberSuggestionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserNumberSuggestionResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserNumberSuggestionResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/next-number-after": {
      "get": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Suggest the next resident number after userNumber using the bank's first NumberFormats entry.",
        "description": "Same access and non-reserving behavior as GetBankUserNumberForNewUser. userNumber is required and must match the configured segment lengths and ranges; otherwise 400 number-format. Tests up to nine candidates; empty number means no suggestion. Missing format returns an empty number; malformed stored settings return 503.",
        "operationId": "GetBankNextUserNumber",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userNumber",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserNumberSuggestionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserNumberSuggestionResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserNumberSuggestionResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/{userKid}/workspace": {
      "get": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Read authoritative editing fields and an opaque concurrency revision. Bank-wide Users2/User Read required.",
        "description": "### Access\r\n            \r\n- Requires an active manager, **Users2**, **User Read** and a **bank-wide grant**.\r\n- Send canonical bank and resident KIDs belonging to this site and the same bank.\r\n            \r\n### Result\r\n            \r\n- Returns authoritative editing fields, permitted operation flags and an opaque concurrency `revision`.\r\n- Use this revision when calling `ExecuteBankUserCommand`.\r\n- **HTTP 404:** resident missing or outside the caller's deletion retention.",
        "operationId": "GetBankUserWorkspace",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/{userKid}/activation": {
      "get": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Read the resident activation code for printing. Requires bank-wide Users2/User Create.",
        "description": "### Access\r\n            \r\n- Requires an active manager, **Users2**, **User Read**, **User Create** and a **bank-wide grant**.\r\n- Send canonical bank and resident KIDs belonging to this site and the same bank.\r\n            \r\n### Result\r\n            \r\n- Returns the active resident's activation code, name and number for printing.\r\n- `qrCodeDataV1` contains the tenant URL and a FlexCipherLongs fragment with bank code, user code and UTC seconds since 2000-01-01, matching FlexORM GetQRCodeString.\r\n- `qrCodeDataV2` uses the same URL and timestamp, with a fourth value (random noise, 0–1073741823) and a fifth value: 30-bit checksum = (((bankCode * 31 + userCode) * 31 + seconds) * 31 + noise) modulo 1073741824; reduce inputs modulo 1073741824 before arithmetic to avoid overflow. Decode with FlexCipherLongs.Parse(5, fragment) and verify the checksum. It is error detection, not authentication; existing version 1 consumers must explicitly support version 2.\r\n- Encode the complete string unchanged as a QR code in the client; the API returns no image. Empty means no tenant activation URL is configured.\r\n- Treat both codes as credentials: do not log, cache or send them to external QR services. Reload to obtain a fresh timestamp; validity is determined by the existing activation consumer.\r\n- **HTTP 404:** resident missing or deleted.",
        "operationId": "GetBankUserActivation",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserActivationResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserActivationResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserActivationResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/banks/{bankKid}/users/{userKid}/commands": {
      "post": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Execute profile, icon, attributes, tag, location, delete, restore or replace with the revision from GetBankUserWorkspace.",
        "description": "### Access and revision\r\n            \r\n- Every command requires **Users2**, **User Read** and a **bank-wide grant**.\r\n- Send the `revision` returned by `GetBankUserWorkspace`.\r\n            \r\n### Required User permissions\r\n            \r\n- **Profile:** Rename / RenameExtrenatId for the changed fields.\r\n- **Icon / attributes:** Write.\r\n- **Icon:** send `action: \"icon\"`, `icon` (an exact eIcon name with eIconSubject.Person metadata) and `revision`.\r\n  Read `availableIcons` from GetBankUserWorkspace; an existing non-Person icon is display-only.\r\n  The confirmed response includes `icon`, `availableIcons`, `canEditIcon` and the new `revision`.\r\n  Numeric values, URLs and non-Person assignments return 400; deleted residents cannot be edited.\r\n- **Delete / restore:** Delete.\r\n- **Replace:** Delete and Create.\r\n- **Create / tag / location:** Create.\r\n            \r\n### Conflicts and synchronization\r\n            \r\n- **HTTP 409:** reload and review the current data before retrying.\r\n- Successful changes schedule existing backend synchronization, not instant hardware confirmation.\r\n- Resident data and synchronization use **Log tables exclusively**. No notification or billing operation is executed.\r\n- Disabled, unconfigured or nontransactional storage returns **HTTP 503**.",
        "operationId": "ExecuteBankUserCommand",
        "parameters": [
          {
            "name": "bankKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCommandRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCommandRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UserCommandRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserWorkspaceResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/users/export-count": {
      "get": {
        "tags": [
          "UserDirectory"
        ],
        "summary": "Count the complete filtered export selection using the same directory authorization and visibility.",
        "description": "No paging parameters. Reuses listing filters and authorization, using a direct aggregate or minimal cached index instead of enumerating pages. No-store; existing storage deadlines and index bounds apply. Concurrent edits can invalidate an export count.",
        "operationId": "GetUserExportCount",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryExportCountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/users": {
      "get": {
        "tags": [
          "UserDirectory"
        ],
        "summary": "List authorized residents for UserFinder1 (77).",
        "description": "Requires UserFinder1, User Read and tenant-bound bank/location grants. Reads Log7 only.\r\n            Applies RetentionDays and existing resident location visibility. enabledOnly=true excludes deleted residents;\r\n            residents have no Enabled setting. filter (0–128 characters) matches literal name/number substrings,\r\n            exact email/SMS or canonical/readable resident KID. sort=identity (default, numeric bank/user order), name or number; direction=asc or desc; pageSize=1–250.\r\n            Cursor is protected, manager/scope/query-bound and expires after 15 minutes. Keep options unchanged.\r\n            Up to 1000 candidates per request; scanLimitReached may accompany a short/empty page. Follow nextCursor.\r\n            Concurrent edits can move rows. No total count. Bank KIDs provide identity, not additional bank metadata.\r\n            Existing GetBankUsers with an exact userKid can open a result under UserFinder1; bulk lists and mutations\r\n            retain Users2 requirements. 400 invalid query/cursor, 401 revoked session, 403 missing access, 503 unavailable.",
        "operationId": "GetUsers",
        "parameters": [
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "identity"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "enabledOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserDirectoryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserDirectoryResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserDirectoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/users/count": {
      "get": {
        "tags": [
          "UserDirectoryCount"
        ],
        "summary": "Count active authorized residents for the UserFinder1 badge.",
        "description": "Requires current active manager, UserFinder1 and User Read. Applies the trusted tenant's bank/location\r\n            grants and the same resident location decoding as GetUsers. Counts only nondeleted residents, independently of\r\n            the current filter/page. The count is an approximate display value cached for up to 24 hours per exact resource\r\n            scope in this API process; restart/eviction causes a fresh count. Never use it for authorization or accounting.\r\n            Session/tab/permission/scope are rechecked before every cache access. Log7 only, no writes. First count has a\r\n            12-second deadline; 401 revoked session, 403 missing access, 503 unavailable, never a fabricated zero.",
        "operationId": "GetUserCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PeopleDirectoryCount"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/users/{userKid}/receipts": {
      "get": {
        "tags": [
          "UserReceipts"
        ],
        "summary": "Read complete receipts for one resident, newest first, twenty receipts at a time.",
        "description": "Requires an active site-bound manager, Users2, User Read and a bank-wide KID grant.\r\nThe canonical resident KID cannot select another tenant. Deleted-resident retention applies.\r\n            \r\nThe current and latest 24 stored period numbers are considered, within accounting/surveillance retention.\r\nPurchases, payments, discounts and calculated transfers to rent are separate groups. Zero-total\r\ndocuments and Month lines are omitted. Currencies are separate; no conversion takes place.\r\nAmounts are signed minor units: a purchase is positive, a payment/discount normally negative.\r\nReceipt balances exclude the unused current discount included in GetBankUserBalances.\r\nCalculated adjustments have no transaction KID. Missing VAT or currency is null, never assumed zero/DKK.\r\nOccurredAt includes the location's UTC offset; Date is its local calendar date.\r\n            \r\nFirst request: offset=0 without revision. Continue with nextOffset and the unchanged revision.\r\nHTTP 409 receipts-changed requires discarding older pages and restarting at offset zero.\r\nOffsets count entire receipt groups. No group is split between pages. No background polling is required.\r\n            \r\nEach request uses one read-only snapshot, at most 50,000 postings / 8 MiB of stored text and a\r\n12-second storage deadline. Only two reads run concurrently per API process. Oversized history\r\nreturns 503 receipts-too-large, never partial totals. Missing/hidden resident: 404 not-found.\r\nOther errors: 400 invalid-user/invalid-page, 401, 403 forbidden, 503 storage-unavailable/storage-timeout/storage-busy.",
        "operationId": "GetUserReceipts",
        "parameters": [
          {
            "name": "userKid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0
            }
          },
          {
            "name": "revision",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/UserReceiptsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserReceiptsResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserReceiptsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/users": {
      "get": {
        "tags": [
          "UserSearch"
        ],
        "summary": "Search resident Number, Name, Email, SMS and partial numeric TagId using current Log7.",
        "description": "### Access and identifiers\r\n            \r\n- Requires **Users2**, **User Read** and site/bank/location grants.\r\n- Only **BankId ≥ 1000**, ordinary users and records visible under **RetentionDays**.\r\n- An exact canonical or readable resident KID (`tenant.bank-user` or `bank-user` with the trusted site tenant) uses an exact bank/user lookup; `matchedSetting` is `Kid`.\r\n- Cross-tenant or inaccessible identities return no results.\r\n            \r\n### Text matching\r\n            \r\n- Query length: **2–128 characters**, literal and case-insensitive.\r\n- **Number and email:** exact text.\r\n- **Name:** substring matching.\r\n- **TagId:** substring matching for positive decimal input; optional spaces are accepted.\r\n- Use `SearchUserSms` for the independent complete-phone-number lookup.\r\n            \r\n### KID-only lookup\r\n            \r\n- `kidOnly=true` accepts only a complete resident KID and skips ordinary text search.\r\n- Invalid input returns no items without business storage. Existing authorization still applies.\r\n            \r\n### Results and parent banks\r\n            \r\n- At most **50 resident matches**; up to **501 candidates** are checked.\r\n- `hasMore` also asks callers to refine broad queries when the candidate bound is reached.\r\n- `matchedSetting` and `matchedValue` explain each match.\r\n- When Bank Read is granted, includes distinct parent banks with `isContext=true`.\r\n- Limit and `hasMore` count residents. **Merge all result types by KID.**\r\n            \r\n### Deadlines and cache\r\n            \r\n- Name/Tag queries allow **10 seconds SQL** and **12 seconds including cache wait**.\r\n- Cache: **60 seconds** per bank scope/query. Current permissions are reapplied.",
        "operationId": "SearchUsers",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kidOnly",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/user-sms": {
      "get": {
        "tags": [
          "UserSearch"
        ],
        "summary": "Search complete resident SMS numbers with indexed exact Log7 Text matches.",
        "description": "### Access and matching\r\n            \r\n- Uses the same authorization, retention, parent bank context and result bounds as `SearchUsers`.\r\n- Searches complete resident SMS numbers with **indexed exact Log7 Text matches**.\r\n- Accepts **8–15 digits**, spaces, hyphens, parentheses and an optional leading `+` or international `00`.\r\n- Danish eight-digit numbers match both with and without `45`.\r\n            \r\n### Independent lookup\r\n            \r\n- Runs independently of substring and TagId search.\r\n- Does not decode activation codes or charge the activation-code quota.",
        "operationId": "SearchUserSms",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    },
    "/api/v1/search/user-activation": {
      "get": {
        "tags": [
          "UserSearch"
        ],
        "summary": "Decode an ordinary resident activation code and resolve name and icon from current Log7.",
        "description": "### Access and lookup\r\n            \r\n- Uses the same permissions as `SearchUsers`.\r\n- Codes contain bank/user, not tenant; the **trusted site supplies the tenant**.\r\n- Resolves the ordinary resident's name and icon from current **Log7**.\r\n- Invalid, missing, deleted-outside-retention or inaccessible residents return no items.\r\n            \r\n### Shared activation-code rate limit\r\n            \r\n- All bank, location and resident code endpoints share **5 calls per 10 minutes** and **20 per hour**, per manager.\r\n- Invalid attempts count.\r\n- **HTTP 429** includes `Retry-After`; wait before trying again.",
        "operationId": "SearchUserActivation",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ManagerBearer": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AccountDocumentResponse": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "nullable": true
          },
          "docId": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountEntryResponse"
            },
            "nullable": true
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountTotal"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A receipt assembled from this page's authorized lines. Further pages can contain more lines with the same key."
      },
      "AccountEntryResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "userKid": {
            "type": "string",
            "nullable": true
          },
          "recordedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "transactionType": {
            "type": "string",
            "nullable": true
          },
          "period": {
            "type": "integer",
            "format": "int32"
          },
          "reversed": {
            "type": "boolean"
          },
          "reversalOfKid": {
            "type": "string",
            "nullable": true
          },
          "userName": {
            "type": "string",
            "nullable": true
          },
          "userNumber": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          },
          "canReverse": {
            "type": "boolean"
          },
          "unitIconKid": {
            "type": "string",
            "description": "API-computed unit icon identity, ready for the image URL.",
            "nullable": true
          },
          "documentKey": {
            "type": "string",
            "description": "Opaque bank-scoped receipt key, shared by lines belonging to the same document.",
            "nullable": true
          },
          "documentId": {
            "type": "integer",
            "description": "Positive decoded DocId; null for standalone, malformed or payment-managed lines.",
            "format": "int32",
            "nullable": true
          },
          "isAnonymized": {
            "type": "boolean",
            "description": "Identity and free text were masked by the effective retention settings."
          },
          "paymentKind": {
            "type": "string",
            "description": "Credit, ReserveRefund or Managed for payment-managed lines; empty otherwise. No payment IDs.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One posting, with its original sign/currency and an independently authorized reversal capability."
      },
      "AccountIconResponse": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Most frequent authorized currency and the ready-to-render Forbrug icon."
      },
      "AccountResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountEntryResponse"
            },
            "nullable": true
          },
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountUnitResponse"
            },
            "nullable": true
          },
          "periods": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "nullable": true
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountTotal"
            },
            "nullable": true
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "through": {
            "type": "string",
            "format": "date"
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "period": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountDocumentResponse"
            },
            "description": "FlexOrm-style receipt grouping of this page. Items/offset/limit remain posting-based.",
            "nullable": true,
            "readOnly": true
          }
        },
        "additionalProperties": false,
        "description": "Filtered postings, full-selection totals and server-resolved query defaults. No computed resident balance is implied."
      },
      "AccountRevisionResponse": {
        "type": "object",
        "properties": {
          "revision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Opaque revision of the filtered posting set; not an insertion time, cursor or access grant."
      },
      "AccountTotal": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "nullable": true
          },
          "entries": {
            "type": "integer",
            "format": "int64"
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false
      },
      "AccountUnitResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Scoped choices for the location and machine filters."
      },
      "ActiveBankCountResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          },
          "iconKid": {
            "type": "string",
            "description": "Tab icon containing the authorized count.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Accessible bank count for Enabled=1 and Deleted=0."
      },
      "ActiveLocationCountResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          },
          "iconKid": {
            "type": "string",
            "description": "Ready-to-render Locations1 icon with Count in Kid.Count.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Number of accessible locations with Enabled=1 and Deleted=0, independent of search and paging."
      },
      "ActiveUnitCountResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Accessible active units or terminals, independent of search and paging, with a ready-to-render navigation icon."
      },
      "AssistantLink": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "bankKid": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A portal link derived from an authorized API result, never from generated HTML."
      },
      "AssistantMessage": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "nullable": true
          },
          "content": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A prior visible message. History is untrusted context, never authorization or evidence."
      },
      "AssistantRequest": {
        "required": [
          "question"
        ],
        "type": "object",
        "properties": {
          "question": {
            "maxLength": 2000,
            "minLength": 1,
            "type": "string",
            "description": "The required question, between 1 and 2000 characters."
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssistantMessage"
            },
            "description": "Optional prior visible messages; always treated as untrusted context.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A bounded question with optional visible conversation history; no tenant selector."
      },
      "AssistantResponse": {
        "type": "object",
        "properties": {
          "answer": {
            "type": "string",
            "nullable": true
          },
          "operations": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssistantLink"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Plain text answer, executed operation IDs and server-verified object links."
      },
      "BankDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          },
          "deleted": {
            "type": "boolean",
            "nullable": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "nullable": true
            },
            "description": "Requested bank-level settings; null when scope does not authorize their disclosure.\r\n            bankActivationCode additionally requires whole-tenant access and Bank Create.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Canonical bank identity, display metadata and stored state."
      },
      "BankDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankDirectoryItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Selected optional field keys. Keep the same selection when following the cursor.",
            "nullable": true
          },
          "canReadBankActivationCode": {
            "type": "boolean",
            "description": "Whether this caller may display, search and sort bank activation codes."
          }
        },
        "additionalProperties": false,
        "description": "A bounded bank page and optional protected continuation."
      },
      "BankDocumentItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical document KID.",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "description": "Canonical location KID.",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "description": "Canonical unit KID.",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "description": "Current location name.",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "description": "Current unit name.",
            "nullable": true
          },
          "unitType": {
            "type": "integer",
            "description": "Decoded unit type, when known.",
            "format": "int32",
            "nullable": true
          },
          "lastActivityUtc": {
            "type": "string",
            "description": "Latest Cycle timestamp within the requested interval, in UTC.",
            "format": "date-time"
          },
          "unitIconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One document identity with authorized display metadata and the latest matching Cycle time."
      },
      "BankDocumentPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankDocumentItem"
            },
            "description": "Documents in descending activity order.",
            "nullable": true
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankLocationResponse"
            },
            "description": "Visible, authorized locations in the bank.",
            "nullable": true
          },
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentUnitOption"
            },
            "description": "Visible units within the selected location scope.",
            "nullable": true
          },
          "from": {
            "type": "string",
            "description": "Effective inclusive search start.",
            "format": "date-time"
          },
          "through": {
            "type": "string",
            "description": "Effective inclusive search end.",
            "format": "date-time"
          },
          "offset": {
            "type": "integer",
            "description": "Effective offset.",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "description": "Effective page size.",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean",
            "description": "Another page existed when this query ran."
          }
        },
        "additionalProperties": false,
        "description": "One bounded result page and authorized filter choices."
      },
      "BankIconResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "offline": {
            "type": "boolean",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Null offline means empty/incomplete status, never confirmed online."
      },
      "BankIconsResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankIconResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bounded, independently authorized bank icon results."
      },
      "BankLocationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical site-bound location KID.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Location name, possibly empty.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Location display metadata; KID is its sole object identifier."
      },
      "BankLocationStatusResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical site-bound location KID.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Location name, possibly empty.",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "True only when the stored Enabled value is exactly 1."
          },
          "deleted": {
            "type": "boolean",
            "description": "True for a positive Deleted MS2000 value; null for malformed values (visible only with a site-wide grant).",
            "nullable": true
          },
          "deletedAt": {
            "type": "string",
            "description": "UTC deletion timestamp, or null for zero or an unrepresentable value.",
            "format": "date-time",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bank overview location metadata with the same status fields as GetLocations."
      },
      "BankNavigationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical bank KID in this site's tenant.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Bank eSetting.Name, empty when absent.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Display metadata only, not a bank detail record or permission."
      },
      "BankUserResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserLocationResponse"
            },
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserTagResponse"
            },
            "nullable": true
          },
          "attributes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserAttributeResponse"
            },
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "sms": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Current user settings. Missing Deleted means not deleted; Icon is an eIcon name, default user. Email and Sms are decoded from Log7 eSetting.Email and eSetting.SMS, empty when absent. Sms is the stored phone number, not a delivery operation."
      },
      "BankUsersResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankUserResponse"
            },
            "nullable": true
          },
          "previousCursor": {
            "type": "string",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "scanLimitReached": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "A bounded ascending user page. Cursors are opaque positions, never access grants."
      },
      "BookingCommand": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Explicit desired operation, never a toggle that could reverse itself on retry."
      },
      "BookingResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "userKid": {
            "type": "string",
            "nullable": true
          },
          "startLocal": {
            "type": "string",
            "nullable": true
          },
          "endLocal": {
            "type": "string",
            "nullable": true
          },
          "weeklyMinute": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "durationMinutes": {
            "type": "integer",
            "format": "int32"
          },
          "recordedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "cancelled": {
            "type": "boolean"
          },
          "synced": {
            "type": "boolean"
          },
          "source": {
            "type": "string",
            "nullable": true
          },
          "userName": {
            "type": "string",
            "nullable": true
          },
          "userNumber": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          },
          "canCancel": {
            "type": "boolean"
          },
          "canRestore": {
            "type": "boolean"
          },
          "unitIconKid": {
            "type": "string",
            "description": "API-computed unit icon identity, ready for the image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Current Log5 event. Local timestamps have no UTC offset; weekly positions have no absolute date."
      },
      "BookingRuleUnit": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A canonical authorized unit identity with its localized name."
      },
      "BookingUnitResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Canonical scope identifiers and localized labels for a unit filter."
      },
      "BookingsResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookingResponse"
            },
            "nullable": true
          },
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookingUnitResponse"
            },
            "nullable": true
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "through": {
            "type": "string",
            "format": "date"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "A bounded page; dates apply to ordinary reservation starts, while weekly entries are always included."
      },
      "CameraAvailabilityResponse": {
        "type": "object",
        "properties": {
          "hasCaptures": {
            "type": "boolean"
          },
          "isDegraded": {
            "type": "boolean"
          },
          "canCapture": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Availability and effective capture permission for one exact authorized resource."
      },
      "CameraCaptureItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "captureId": {
            "type": "string",
            "nullable": true
          },
          "resourceKid": {
            "type": "string",
            "nullable": true
          },
          "ownerKid": {
            "type": "string",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "capturedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "hasPreview": {
            "type": "boolean"
          },
          "hasMotion": {
            "type": "boolean"
          },
          "hasPlayback": {
            "type": "boolean"
          },
          "bankName": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One authorized capture; all object identifiers are canonical KIDs or opaque API tokens."
      },
      "CameraCapturePage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CameraCaptureItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "isDegraded": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "One bounded page. A degraded page may omit captures from an unavailable region; refresh from the beginning after recovery."
      },
      "CameraConfirmationRequest": {
        "type": "object",
        "properties": {
          "uploadToken": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The unchanged signed ticket returned by PrepareCameraCapture."
      },
      "CameraConfirmationResponse": {
        "type": "object",
        "properties": {
          "confirmed": {
            "type": "boolean"
          },
          "errorCode": {
            "type": "string",
            "nullable": true
          },
          "processingPercent": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Only Confirmed=true acknowledges durable publication. ProcessingPercent is a weighted completed-stage estimate, not elapsed time; null means unknown and 100 requires confirmation. ErrorCode may report a transient processing failure."
      },
      "CameraPrepareRequest": {
        "type": "object",
        "properties": {
          "resourceKid": {
            "type": "string",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "originalFileName": {
            "type": "string",
            "nullable": true
          },
          "originalNameAvailable": {
            "type": "boolean"
          },
          "capturedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "mediaLength": {
            "type": "integer",
            "format": "int64"
          },
          "mediaSha256": {
            "type": "string",
            "nullable": true
          },
          "sensorData": {
            "type": "object",
            "description": "Available device observations with source, time and units; use an empty object when unavailable. Never include API credentials."
          },
          "motionLength": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "motionSha256": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Immutable input for recorded photo, video or a paired Live Photo; tenant and owner are never client parameters."
      },
      "CameraPrepareResponse": {
        "type": "object",
        "properties": {
          "uploadToken": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Opaque signed ticket; retry with this exact token and unchanged original bytes."
      },
      "CameraResourceResponse": {
        "type": "object",
        "properties": {
          "resourceKid": {
            "type": "string",
            "description": "Canonical, site-bound bank, location or unit identity.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Resource display name; unit localization placeholders are resolved.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity including the resource number; use unchanged in icon URLs.",
            "nullable": true
          },
          "requiresProximityCheck": {
            "type": "boolean",
            "description": "True for locations and units; false for banks. Advisory only."
          },
          "latitude": {
            "type": "number",
            "description": "Nullable location latitude in decimal degrees, inherited by units.",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "description": "Nullable location longitude in decimal degrees, inherited by units.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Display metadata for the exact authorized camera resource, without parent or child data."
      },
      "CameraSaveResponse": {
        "type": "object",
        "properties": {
          "captureId": {
            "type": "string",
            "nullable": true
          },
          "resourceKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A complete media set exists in at least one region; the second copy continues independently."
      },
      "DatabaseAccessResponse": {
        "type": "object",
        "properties": {
          "canWrite": {
            "type": "boolean",
            "description": "True: Log7 read/append privilege check succeeded. False: read succeeds but the write connection is absent, denies access or is read-only. Null: status could not be determined. Checks shared Log7 and bank-zero Log7 history only; bank grants, triggers and transactions may differ.",
            "nullable": true
          },
          "checkedAtUtc": {
            "type": "string",
            "description": "When this cached check was started. Known results are cached for ten minutes; unknown results for one minute.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Site database access indicator, never a manager permission or a guarantee for a business operation."
      },
      "DirectoryExportCountResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "The complete number of rows matching the authorized export selection."
      },
      "DocumentCell": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "text": {
            "type": "string",
            "nullable": true
          },
          "isCalculated": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Finite numeric interpretation alongside original text; calculated values have no original text."
      },
      "DocumentColumn": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "localization": {
            "type": "string",
            "nullable": true
          },
          "color": {
            "type": "string",
            "nullable": true
          },
          "onlyNumericValues": {
            "type": "boolean"
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stable enum column metadata; kind is state or setting."
      },
      "DocumentNeighbor": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "lastActivityUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "An existing same-unit document identified by its canonical KID and latest tagged Cycle timestamp."
      },
      "DocumentNeighbors": {
        "type": "object",
        "properties": {
          "previous": {
            "$ref": "#/components/schemas/DocumentNeighbor"
          },
          "next": {
            "$ref": "#/components/schemas/DocumentNeighbor"
          }
        },
        "additionalProperties": false,
        "description": "Previous (higher numeric Doc ID) and next (lower numeric Doc ID) documents. Null means no document exists in that direction."
      },
      "DocumentTable": {
        "type": "object",
        "properties": {
          "documentKid": {
            "type": "string",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          },
          "finished": {
            "type": "boolean"
          },
          "fromMs2000": {
            "type": "integer",
            "format": "int64"
          },
          "toMs2000": {
            "type": "integer",
            "format": "int64"
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentColumn"
            },
            "nullable": true
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentTableRow"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Only columns with data are returned, with values indexed by column position. A missing cell is null; a stored null is a cell with null text/value."
      },
      "DocumentTableRow": {
        "type": "object",
        "properties": {
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "cells": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentCell"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One exact MS2000 timestamp with cells in column order."
      },
      "DocumentUnitOption": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical unit KID.",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "description": "Canonical location KID.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Current unit name.",
            "nullable": true
          },
          "unitType": {
            "type": "integer",
            "description": "Decoded unit type, when known.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Visible unit filter choice."
      },
      "HostingBandwidth": {
        "type": "object",
        "properties": {
          "dateUtc": {
            "type": "string",
            "format": "date"
          },
          "bytes": {
            "type": "string",
            "nullable": true
          },
          "errorCode": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Previous UTC day's total; Bytes is an unsigned decimal string to preserve uint64 precision."
      },
      "HostingLogsResponse": {
        "type": "object",
        "properties": {
          "environment": {
            "type": "string",
            "description": "beta or production.",
            "nullable": true
          },
          "application": {
            "type": "string",
            "description": "portal-api, equipment-api or portal-web.",
            "nullable": true
          },
          "fetchedAtUtc": {
            "type": "string",
            "description": "Time of the provider snapshot, not the event timestamp.",
            "format": "date-time"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "At most 100 plain-text lines; untrusted output, never HTML.",
            "nullable": true
          },
          "truncated": {
            "type": "boolean",
            "description": "True when the local byte/line bound removed content."
          }
        },
        "additionalProperties": false,
        "description": "A bounded snapshot of shared application runtime output, for designated operators only."
      },
      "HostingMetric": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "nullable": true
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostingSeries"
            },
            "nullable": true
          },
          "errorCode": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A metric in percent or count, kept separate by component and instance; failures have no series."
      },
      "HostingMetricsResponse": {
        "type": "object",
        "properties": {
          "environment": {
            "type": "string",
            "nullable": true
          },
          "application": {
            "type": "string",
            "nullable": true
          },
          "fromUtc": {
            "type": "string",
            "format": "date-time"
          },
          "toUtc": {
            "type": "string",
            "format": "date-time"
          },
          "fetchedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "refreshAfterSeconds": {
            "type": "integer",
            "format": "int32"
          },
          "metrics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostingMetric"
            },
            "nullable": true
          },
          "bandwidth": {
            "$ref": "#/components/schemas/HostingBandwidth"
          }
        },
        "additionalProperties": false,
        "description": "One authorized app/cluster hosting snapshot; never a customer's individual consumption."
      },
      "HostingPoint": {
        "type": "object",
        "properties": {
          "timestampUtc": {
            "type": "string",
            "format": "date-time"
          },
          "value": {
            "type": "number",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A UTC measurement; null means a gap or a non-finite provider sample, never zero."
      },
      "HostingSeries": {
        "type": "object",
        "properties": {
          "component": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostingPoint"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Provider component and instance labels are display text, never resource grants."
      },
      "InstallerDetailsResponse": {
        "type": "object",
        "properties": {
          "installer": {
            "$ref": "#/components/schemas/InstallerDirectoryItem"
          },
          "canEditIcon": {
            "type": "boolean"
          },
          "iconRevision": {
            "type": "string",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authorized installer details and display hints for icon editing. Hints never authorize writes."
      },
      "InstallerDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InstallerLocationResponse"
            },
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InstallerTagResponse"
            },
            "nullable": true
          },
          "deleted": {
            "type": "boolean"
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "nullable": true
          },
          "lastActiveAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "activationCode": {
            "type": "string",
            "description": "User activation code, only when explicitly requested with Installer Create permission.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Installer metadata from the site's Log7 with BankId=TenantId. Kid is canonical with type Installer;\r\n            clients can derive the display UserId from it. Missing Enabled is null. DeletedAt and LastActiveAt are UTC;\r\n            LastActiveAt is the Alive krumb's MS2000, not its Text. Passwords are never returned."
      },
      "InstallerDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InstallerDirectoryItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One installer page. Continue until NextCursor is null, even if Items is empty."
      },
      "InstallerIconRequest": {
        "required": [
          "expectedRevision",
          "icon"
        ],
        "type": "object",
        "properties": {
          "icon": {
            "type": "string",
            "nullable": true
          },
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Desired exact Person icon and the opaque revision from GetInstaller."
      },
      "InstallerIconResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "iconRevision": {
            "type": "string",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authoritative committed icon; update UI only after a complete successful response."
      },
      "InstallerLocationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stored location association in the installer's tenant bank, with Access/NoAccess state.\r\n            Metadata only, never an authorization grant for the caller. Names are not looked up."
      },
      "InstallerTagResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stored tag association, including locked/deleted/history states; state is the eTagState name."
      },
      "LiveLogCard": {
        "type": "object",
        "properties": {
          "server": {
            "type": "string",
            "description": "Fixed server selector.",
            "nullable": true
          },
          "errorCode": {
            "type": "string",
            "description": "Null on success; otherwise live-logs-not-configured or live-logs-unavailable.",
            "nullable": true
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiveLogEvent"
            },
            "description": "Newest events first; at most 100.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One server card; errors contain no transport details."
      },
      "LiveLogEvent": {
        "type": "object",
        "properties": {
          "timestamp": {
            "type": "string",
            "description": "UTC event time.",
            "format": "date-time"
          },
          "level": {
            "type": "string",
            "description": "Logging severity.",
            "nullable": true
          },
          "message": {
            "type": "string",
            "description": "Static message template, not arbitrary state.",
            "nullable": true
          },
          "category": {
            "type": "string",
            "description": "Logger category.",
            "nullable": true
          },
          "statusCode": {
            "type": "integer",
            "description": "Optional HTTP result.",
            "format": "int32",
            "nullable": true
          },
          "elapsedMilliseconds": {
            "type": "integer",
            "description": "Optional server processing time.",
            "format": "int64",
            "nullable": true
          },
          "bankId": {
            "type": "integer",
            "description": "Authorized diagnostic bank identifier.",
            "format": "int32",
            "nullable": true
          },
          "userIds": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Authorized requested resident identifiers.",
            "nullable": true
          },
          "traceId": {
            "type": "string",
            "description": "Correlation identifier.",
            "nullable": true
          },
          "question": {
            "type": "string",
            "description": "Optional approved chat question text, at most 2000 characters.",
            "nullable": true
          },
          "fields": {
            "type": "object",
            "additionalProperties": { },
            "description": "Sanitized structured values for message-template placeholders.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One sanitized event from the bounded process-local buffer."
      },
      "LiveLogsResponse": {
        "type": "object",
        "properties": {
          "tenantKid": {
            "type": "string",
            "description": "Canonical tenant KID.",
            "nullable": true
          },
          "fetchedAtUtc": {
            "type": "string",
            "description": "UTC snapshot time.",
            "format": "date-time"
          },
          "refreshAfterSeconds": {
            "type": "integer",
            "description": "Minimum polling interval.",
            "format": "int32"
          },
          "servers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiveLogCard"
            },
            "description": "Portal API, Equipment API and Portal Web.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authorized current-tenant snapshot for three server cards."
      },
      "LocationBookingCalendarDayResponse": {
        "type": "object",
        "properties": {
          "dayOfWeek": {
            "type": "integer",
            "format": "int32"
          },
          "slots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingCalendarSlotResponse"
            },
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date"
          }
        },
        "additionalProperties": false,
        "description": "DayOfWeek is 0=Sunday through 6=Saturday; times are relative to this day's midnight."
      },
      "LocationBookingCalendarGroup": {
        "type": "object",
        "properties": {
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingCalendarUnit"
            },
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingCalendarDayResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Units with the same valid stored calendar identity and effective dated schedule; status is Configured."
      },
      "LocationBookingCalendarSlotResponse": {
        "type": "object",
        "properties": {
          "startMinute": {
            "type": "integer",
            "format": "int32"
          },
          "durationMinutes": {
            "type": "integer",
            "format": "int32"
          },
          "type": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Local wall-clock minutes; Type is 0=reservation period, 1=chance period, 2=closed, 3=unknown."
      },
      "LocationBookingCalendarUnit": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authorized canonical unit KID and localized plain-text name."
      },
      "LocationBookingCalendarsResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingCalendarGroup"
            },
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "days": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "The authorized location's effective dated calendars; no occupancy or booking rights."
      },
      "LocationBookingRule": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "text": {
            "type": "string",
            "nullable": true
          },
          "warning": {
            "type": "boolean"
          },
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingRulePart"
            },
            "description": "Optional ordered plain-text parts. Concatenate text without separators to reproduce Text;\r\n            clients may emphasize values. Fall back to Text when parts are absent or empty. Never markup.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stable code, localized plain text and whether the row needs attention. Never HTML."
      },
      "LocationBookingRuleGroup": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookingRuleUnit"
            },
            "nullable": true
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingRule"
            },
            "nullable": true
          },
          "common": {
            "type": "boolean"
          },
          "help": {
            "type": "string",
            "description": "Optional localized explanation of how the section applies to its units.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Localized heading/help, authorized units and rules for a compact display section."
      },
      "LocationBookingRulePart": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "nullable": true
          },
          "isValue": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Plain text and a semantic value flag; presentation is the client's responsibility."
      },
      "LocationBookingRulesResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "calculatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationBookingRuleGroup"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authorized configured booking rules, observed at calculatedAt. Not a booking availability decision."
      },
      "LocationCountResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "Exact number of locations matching the authorized, filtered directory at count time."
      },
      "LocationDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "bankKid": {
            "type": "string",
            "nullable": true
          },
          "bankName": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "vismaCustNo": {
            "type": "string",
            "nullable": true
          },
          "bankActivationCode": {
            "type": "string",
            "nullable": true
          },
          "locationActivationCode": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          },
          "deleted": {
            "type": "boolean",
            "nullable": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "latitude": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "teltonikaSms": {
            "type": "string",
            "nullable": true
          },
          "alternativeBankName": {
            "type": "string",
            "nullable": true
          },
          "mask": {
            "type": "string",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "online": {
            "type": "boolean",
            "nullable": true
          },
          "lastContactAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "vismaCrAcNo": {
            "type": "string",
            "nullable": true
          },
          "vismaInvoiceVersion": {
            "type": "string",
            "nullable": true
          },
          "vismaOrdre": {
            "type": "string",
            "nullable": true
          },
          "vismaPNTurnover": {
            "type": "string",
            "nullable": true
          },
          "vismaPNSettlement": {
            "type": "string",
            "nullable": true
          },
          "vismaSettlement": {
            "type": "string",
            "nullable": true
          },
          "vismaVAT": {
            "type": "string",
            "nullable": true
          },
          "vismaServiceKey": {
            "type": "string",
            "nullable": true
          },
          "vismaStart": {
            "type": "string",
            "nullable": true
          },
          "vismaNote": {
            "type": "string",
            "nullable": true
          },
          "hiddenNote": {
            "type": "string",
            "nullable": true
          },
          "vismaGuaranteeMonth": {
            "type": "string",
            "nullable": true
          },
          "vismaGuaranteeUnder": {
            "type": "string",
            "nullable": true
          },
          "vismaGuarantee": {
            "type": "string",
            "nullable": true
          },
          "vismaGuaranteeCustomer": {
            "type": "string",
            "nullable": true
          },
          "vismaGuaranteeOver": {
            "type": "string",
            "nullable": true
          },
          "gift": {
            "type": "string",
            "nullable": true
          },
          "giftBegin": {
            "type": "string",
            "nullable": true
          },
          "giftEnd": {
            "type": "string",
            "nullable": true
          },
          "giftSplit": {
            "type": "string",
            "nullable": true
          },
          "giftPN": {
            "type": "string",
            "nullable": true
          },
          "soapEnd": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          },
          "bankIconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bank and location identifiers are canonical KIDs. Activation codes are null without the required Create permission and scope."
      },
      "LocationDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationDirectoryItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "hasAllBanksAccess": {
            "type": "boolean"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One authorized location page. Continue with NextCursor until null."
      },
      "LocationIconResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "offline": {
            "type": "boolean",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Null offline means empty or incomplete status, never a confirmed online location."
      },
      "LocationIconsResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationIconResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bounded lazy location icon lookup with independently authorized results."
      },
      "LocationOpeningHoursResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "calculatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpeningHoursGroup"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A location's authorized schedules, calculated at an instant in its local time zone."
      },
      "LocationReservationHistoryItem": {
        "type": "object",
        "properties": {
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "startMinute": {
            "type": "integer",
            "format": "int32"
          },
          "durationMinutes": {
            "type": "integer",
            "format": "int32"
          },
          "revision": {
            "type": "integer",
            "format": "int64"
          },
          "cancelled": {
            "type": "boolean"
          },
          "userNumber": {
            "type": "string",
            "nullable": true
          },
          "userName": {
            "type": "string",
            "nullable": true
          },
          "userKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Unit KID, local epoch start minute, absolute duration, UTC event revision and cancellation state."
      },
      "LocationReservationHistoryResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "days": {
            "type": "integer",
            "format": "int32"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationReservationHistoryItem"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bank reservation history with resident display metadata."
      },
      "LocationReservationResponse": {
        "type": "object",
        "properties": {
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "startMinute": {
            "type": "integer",
            "format": "int32"
          },
          "durationMinutes": {
            "type": "integer",
            "format": "int32"
          },
          "userNumber": {
            "type": "string",
            "nullable": true
          },
          "userName": {
            "type": "string",
            "nullable": true
          },
          "userKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Unit KID, local epoch/weekly start minute and positive duration. No slot rounding."
      },
      "LocationReservationsResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "days": {
            "type": "integer",
            "format": "int32"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationReservationResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Current active reservations, independent of calendar configuration, with resident display metadata."
      },
      "LocationUnitsResponse": {
        "type": "object",
        "properties": {
          "location": {
            "$ref": "#/components/schemas/BankLocationResponse"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnitOverviewResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An authorized location and its visible unit list."
      },
      "LocationWeatherCurrent": {
        "type": "object",
        "properties": {
          "observedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "retrievedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "temperatureCelsius": {
            "type": "number",
            "format": "double"
          },
          "apparentTemperatureCelsius": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "windSpeedMetresPerSecond": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "precipitationMillimetres": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "relativeHumidityPercent": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "weatherCode": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "isDay": {
            "type": "boolean",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Open-Meteo model conditions. Times are UTC; units are explicit in measurement names."
      },
      "LocationWeatherResponse": {
        "type": "object",
        "properties": {
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "positionSource": {
            "type": "string",
            "nullable": true
          },
          "current": {
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/LocationWeatherCurrent"
              }
            ],
            "description": "Current conditions, or null unless status is Available.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Weather for one authorized location. Null measurements mean unknown, never zero."
      },
      "ManagerCreationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The canonical KID of the newly activated empty administrator."
      },
      "ManagerDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical manager KID belonging to the API site, bank zero.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Decoded display name; empty when absent.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Decoded eSetting.Email; empty when absent.",
            "nullable": true
          },
          "resourceGrants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerResourceGrantResponse"
            },
            "description": "Recognized grants on this site; omitted stored tenants are resolved. An identifier never grants access.",
            "nullable": true
          },
          "tabs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerTabResponse"
            },
            "description": "Recognized eTab grants in AttributeMetaSortOrder, then numeric ID order. These are page grants, not effective operation permissions.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          },
          "gravatarUrl": {
            "type": "string",
            "description": "Optional Gravatar image URL when Email is valid; preferred over the stored icon. Uses SHA256, 96px, G rating and d=404; fall back to IconKid on image failure. Browser requests disclose the email hash and client IP to Gravatar.",
            "nullable": true
          },
          "organisation": {
            "type": "string",
            "description": "Decoded eSetting.Organisation, empty when absent.",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "True for Enabled=1, false for 0, null for absent or invalid settings. This field alone does not establish account usability.",
            "nullable": true
          },
          "deleted": {
            "type": "boolean",
            "description": "Whether eSetting.Deleted contains a positive deletion timestamp. Deleted rows require the caller's retention allowance."
          },
          "deletedAt": {
            "type": "string",
            "description": "Deletion time in UTC, or null for a non-deleted manager.",
            "format": "date-time",
            "nullable": true
          },
          "lastActiveAt": {
            "type": "string",
            "description": "Last recorded activity in UTC, from the current eSetting.Alive Log7 row's MS2000 (milliseconds since 2000-01-01 UTC), not Text. Null when absent, nonpositive or outside the supported date range. Reading the directory does not update activity.",
            "format": "date-time",
            "nullable": true
          },
          "operationPermissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerOperationPermissionResponse"
            },
            "description": "The listed manager's six independent Permission*2 masks, including Installer, with the same semantics as GetCurrentManager. Missing/empty values default to Read; malformed values grant nothing. Combine with account state, Tabs and resource grants.",
            "nullable": true
          },
          "retentionDays": {
            "type": "integer",
            "description": "The listed manager's RetentionDays: days of visibility after deletion for otherwise authorized records. Missing values default to 10; invalid or negative values become zero. Explicit zero is preserved. Does not alter the caller's retention or schedule deletion.",
            "format": "int32"
          },
          "isCurrentManager": {
            "type": "boolean",
            "description": "Whether this record belongs to the caller. Own permission edits require the sole active tenant-wide manager exception."
          },
          "canEditPermissions": {
            "type": "boolean",
            "description": "Caller has Managers Write and this is another administrator or the caller is the sole active tenant-wide manager. Display hint only: every write reauthorizes from current Log7."
          },
          "canEditTabs": {
            "type": "boolean",
            "description": "Whether the caller may edit this manager's Tabs, under the same policy as permission editing. A display hint only."
          },
          "canEditProfile": {
            "type": "boolean",
            "description": "Whether the caller may change Name, Organisation, Enabled, Deleted, RetentionDays, Icon and Email. Same fresh authorization and own-card exception as permission editing."
          },
          "profileRevision": {
            "type": "string",
            "description": "Opaque revision of all seven profile settings; send unchanged to SetManagerProfileField.",
            "nullable": true
          },
          "tabsRevision": {
            "type": "string",
            "description": "Opaque concurrency revision of the complete stored Tabs value; copy unchanged to SetManagerTab.",
            "nullable": true
          },
          "kidsRevision": {
            "type": "string",
            "description": "Opaque revision of the complete stored Kids setting; send unchanged to SetManagerKid.",
            "nullable": true
          },
          "canEditKids": {
            "type": "boolean",
            "description": "Whether the caller may edit resource grants. Uses the same policy and own-card exception as other manager changes."
          },
          "availableTabs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerTabResponse"
            },
            "description": "GetManager only: every known eTab except None/Length, numeric aliases deduplicated, ordered by metadata then ID. These are choices, not grants or a list of implemented portal pages.",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "GetManager only: unique eIcon names with eIconSubject.Person metadata, in numeric enum order. The current display icon is prepended if outside this catalog; legacy values are display-only, not new assignments.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Read-only metadata from current bank-zero Log7 settings. Describes the listed manager, never grants the caller permissions. No credentials are returned."
      },
      "ManagerDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerDirectoryItem"
            },
            "description": "At most pageSize visible manager records. Disabled accounts are included; deleted accounts follow requester retention.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Opaque continuation bound to caller, site, page size, filter, sort and direction, or null when finished. Never decode it.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One authorized page in the requested order. Follow NextCursor even when Items is empty."
      },
      "ManagerEmailMatch": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity used when Gravatar is missing or unavailable.",
            "nullable": true
          },
          "gravatarUrl": {
            "type": "string",
            "description": "Preferred optional Gravatar URL, with the same semantics as GetManager.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Another visible administrator sharing the source email; KID is canonical and tenant-bound."
      },
      "ManagerForgotPasswordRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "maxLength": 254,
            "minLength": 0,
            "type": "string",
            "description": "The manager's existing login address, not the temporary delivery override.",
            "format": "email"
          },
          "language": {
            "pattern": "^(en|da|es)$",
            "type": "string",
            "description": "Email language: en (default), da or es.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Requests a recovery email on this API's tenant. Never log the body."
      },
      "ManagerInvitationRequest": {
        "required": [
          "expectedRevision"
        ],
        "type": "object",
        "properties": {
          "expectedRevision": {
            "minLength": 1,
            "pattern": "^[A-Fa-f0-9]{64}$",
            "type": "string",
            "description": "The profileRevision returned by GetManager or the last confirmed profile save."
          },
          "language": {
            "pattern": "^(en|da|es)$",
            "type": "string",
            "description": "Email language: en (default), da or es.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Confirms the profile version shown when sending an invitation; the caller cannot override the recipient or link host."
      },
      "ManagerInvitationResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An invitation was committed to the asynchronous mail queue; it does not confirm delivery."
      },
      "ManagerKidChangeRequest": {
        "required": [
          "expectedRevision",
          "resourceKid"
        ],
        "type": "object",
        "properties": {
          "resourceKid": {
            "type": "string",
            "description": "Canonical KID on this site. Tenant means all banks; Bank means its entire bank; Location means only that location.",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Required: true adds access; false removes this exact scope.",
            "nullable": true
          },
          "expectedRevision": {
            "type": "string",
            "description": "Required kidsRevision from GetManager or the latest acknowledged SetManagerKid response.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Assign or remove a canonical tenant, bank or location grant."
      },
      "ManagerKidChangeResponse": {
        "type": "object",
        "properties": {
          "resourceGrants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerResourceGrantResponse"
            },
            "nullable": true
          },
          "kidsRevision": {
            "type": "string",
            "nullable": true
          },
          "canEditKids": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Authoritative site grants and next revision; CanEditKids=false means lock the entire editor."
      },
      "ManagerLoginErrorResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The disabled, deleted, or account-settings reason; never stored values or credentials.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A known account-state reason returned only after verifying the manager's password."
      },
      "ManagerLoginRequest": {
        "type": "object",
        "properties": {
          "email": {
            "maxLength": 254,
            "minLength": 0,
            "type": "string",
            "description": "Manager email for password login.",
            "format": "email",
            "nullable": true
          },
          "password": {
            "maxLength": 1024,
            "minLength": 0,
            "type": "string",
            "description": "Original manager password.",
            "nullable": true
          },
          "kid": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "description": "Manager login username from Kid.ToUserId (tenant.0-userId), or canonical bank-zero manager KID, on this API's tenant.",
            "nullable": true
          },
          "apiKey": {
            "maxLength": 512,
            "minLength": 0,
            "type": "string",
            "description": "Original case-sensitive API key, never its hash.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Exactly one manager credential pair submitted over HTTPS. Never log this body."
      },
      "ManagerOperationPermissionResponse": {
        "type": "object",
        "properties": {
          "resource": {
            "type": "string",
            "description": "Managers, Bank, Location, Unit, User, Installer, Service, Tabs or Kids. Match by resource name, not array position.",
            "nullable": true
          },
          "level": {
            "type": "string",
            "description": "Enum text (possibly numeric for combinations), or null for invalid values. Use flags and capability booleans; missing values become Read.",
            "nullable": true
          },
          "canRead": {
            "type": "boolean",
            "description": "Whether reading is permitted at this operation level."
          },
          "canWrite": {
            "type": "boolean",
            "description": "Whether modification is permitted at this operation level."
          },
          "canCreate": {
            "type": "boolean",
            "description": "Whether creation is permitted at this operation level."
          },
          "flags": {
            "type": "integer",
            "description": "Numeric bitmask: Read=1, Write=2, Create=4, Delete=8, RenameExtrenatId=16, Rename=32. None=0; null is invalid.",
            "format": "int32",
            "nullable": true
          },
          "canDelete": {
            "type": "boolean",
            "description": "Whether Delete is explicitly granted."
          },
          "canRenameExternalId": {
            "type": "boolean",
            "description": "Whether RenameExtrenatId is explicitly granted."
          },
          "canRename": {
            "type": "boolean",
            "description": "Whether Rename is explicitly granted."
          }
        },
        "additionalProperties": false,
        "description": "A resource category's independent ePermission2 flags."
      },
      "ManagerPasswordResetResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A language-independent recovery result; never identifies a matching account."
      },
      "ManagerPermissionChangeRequest": {
        "required": [
          "expectedFlags"
        ],
        "type": "object",
        "properties": {
          "flag": {
            "type": "integer",
            "description": "Exactly one ePermission2 bit (1, 2, 4, 8, 16 or 32), required.",
            "format": "int32",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "The desired state of that bit, required.",
            "nullable": true
          },
          "expectedFlags": {
            "type": "integer",
            "description": "Required, including explicit null for an invalid stored mask. Read from GetManager.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Change one independent operation bit using the last displayed flags for concurrency."
      },
      "ManagerPermissionRoleRequest": {
        "required": [
          "expectedFlags",
          "role"
        ],
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "description": "accounting, caretaker, operator, technical-support, tenant-installer, tenant-accounting or combine; case-sensitive, required.",
            "nullable": true
          },
          "expectedFlags": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "format": "int32",
              "nullable": true
            },
            "description": "Exactly Managers, Installer, Service, Bank, Location, Unit, User, Tabs and Kids with last displayed flags. Explicit null represents an invalid stored mask.",
            "nullable": true
          },
          "expectedTabsRevision": {
            "type": "string",
            "description": "Required for accounting and combine: tabsRevision from GetManager or the last acknowledged edit.",
            "nullable": true
          },
          "expectedKidsRevision": {
            "type": "string",
            "description": "Required for combine: kidsRevision from GetManager or the last acknowledged edit.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Apply a server-defined role to the complete permission matrix."
      },
      "ManagerPermissionRoleResponse": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "description": "The applied preset identity.",
            "nullable": true
          },
          "operationPermissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerOperationPermissionResponse"
            },
            "description": "All nine authoritative permission categories.",
            "nullable": true
          },
          "canEditPermissions": {
            "type": "boolean",
            "description": "False when applying the role to yourself removes the required Managers permissions."
          },
          "tabs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerTabResponse"
            },
            "description": "Complete recognized selected tabs after the atomic role assignment.",
            "nullable": true
          },
          "tabsRevision": {
            "type": "string",
            "description": "Revision for the next tab or role edit.",
            "nullable": true
          },
          "canEditTabs": {
            "type": "boolean",
            "description": "False when the change removes your required Managers access."
          },
          "resourceGrants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerResourceGrantResponse"
            },
            "description": "Authoritative resource grants after the role assignment.",
            "nullable": true
          },
          "kidsRevision": {
            "type": "string",
            "description": "Revision for the next resource-grant edit.",
            "nullable": true
          },
          "canEditKids": {
            "type": "boolean",
            "description": "Whether the caller retains permission to edit resource grants."
          }
        },
        "additionalProperties": false,
        "description": "The acknowledged preset and complete persisted permission matrix."
      },
      "ManagerProfileChangeRequest": {
        "required": [
          "expectedRevision",
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "description": "Name/Organisation: string, maximum 200 characters, no controls. Enabled/Deleted: boolean. RetentionDays: integer 0 through 2147483647. Icon: exact eIcon name with eIconSubject.Person metadata. Email: one nonempty address, maximum 254 characters, no whitespace or controls."
          },
          "expectedRevision": {
            "type": "string",
            "description": "Required opaque profileRevision returned by GetManager or the previous successful edit.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One desired profile value plus the profile revision last shown to the caller."
      },
      "ManagerProfileChangeResponse": {
        "required": [
          "email",
          "field",
          "iconKid",
          "name",
          "organisation",
          "profileRevision"
        ],
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "description": "The changed field's stable eSetting name.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Saved display name.",
            "nullable": true
          },
          "organisation": {
            "type": "string",
            "description": "Saved organisation.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Saved login email address. Changing it does not send an invitation or change the password.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "Saved icon identifier. New assignments accept only eIcon names with eIconSubject.Person metadata.",
            "nullable": true
          },
          "gravatarUrl": {
            "type": "string",
            "description": "Optional Gravatar fallback; same semantics as GetManager. Refresh after Email or Icon changes.",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Person icon choices; the current display icon is first when it is outside that catalog.",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Saved Enabled state; null for an unchanged absent/invalid value.",
            "nullable": true
          },
          "deleted": {
            "type": "boolean",
            "description": "True when the saved deletion timestamp is positive."
          },
          "deletedMs2000": {
            "type": "integer",
            "description": "Exact stored deletion value: 0 or milliseconds since 2000-01-01 UTC. Not a Unix timestamp or boolean.",
            "format": "int64"
          },
          "deletedAt": {
            "type": "string",
            "description": "Deletion time in UTC, null when DeletedMs2000 is zero.",
            "format": "date-time",
            "nullable": true
          },
          "retentionDays": {
            "type": "integer",
            "description": "Saved visibility window for deleted records.",
            "format": "int32"
          },
          "profileRevision": {
            "type": "string",
            "description": "Revision for the next profile edit.",
            "nullable": true
          },
          "canEditProfile": {
            "type": "boolean",
            "description": "False after disabling/deleting yourself, or when deletion hides the target under caller retention."
          }
        },
        "additionalProperties": false,
        "description": "Authoritative profile after a confirmed save. A false CanEditProfile locks all editor controls."
      },
      "ManagerProfileResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "The manager ID. Treat it as an opaque, case-sensitive string: store and send it unchanged; do not decode or construct it. An ID does not grant access.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The manager's display name.",
            "nullable": true
          },
          "tabs": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Permitted eTab IDs, not flags. An empty array means no Tabs; it does not prevent login.",
            "nullable": true
          },
          "hasBankAccess": {
            "type": "boolean",
            "description": "Whether at least one bank/location grant applies on this site."
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          },
          "databaseAccess": {
            "$ref": "#/components/schemas/DatabaseAccessResponse"
          },
          "navigationBanks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankNavigationResponse"
            },
            "description": "Navigation labels from Log24 for explicitly scoped banks (including parents of granted locations). Requires Tabs and Bank Read. Empty for tenant-wide access. These labels do not grant bank-wide access; use resourceGrants. Names/icons are cached for one minute.",
            "nullable": true
          },
          "organisation": {
            "type": "string",
            "description": "Optional organisation display text. Empty when absent; never an access grant.",
            "nullable": true
          },
          "gravatarUrl": {
            "type": "string",
            "description": "Optional API-computed Gravatar URL from the current manager's email. Prefer over IconKid; fall back on image failure. Uses SHA256, 96px, G rating and d=404. Direct browser requests disclose the email hash and client IP to Gravatar.",
            "nullable": true
          },
          "retentionDays": {
            "type": "integer",
            "description": "Days after deletion that an otherwise authorized bank, location, unit, user or reservation remains visible. Zero hides deleted objects; missing settings default to 10 days; invalid settings default to zero. Does not grant access or schedule physical deletion.",
            "format": "int32"
          },
          "themeMode": {
            "$ref": "#/components/schemas/eThemeMode"
          },
          "iconSet": {
            "type": "string",
            "description": "Preferred icon set: g or line. Missing or unsupported stored values return line; an explicit g is preserved. This grants no permissions.",
            "nullable": true
          },
          "tabDetails": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerTabResponse"
            },
            "description": "Names and IDs from the shared eTab enum, limited to the manager's recognized grants.",
            "nullable": true
          },
          "resourceGrants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerResourceGrantResponse"
            },
            "description": "Decoded bank/location scopes belonging only to this site. Empty means no bank/location access.",
            "nullable": true
          },
          "operationPermissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerOperationPermissionResponse"
            },
            "description": "Independent operation permissions for Managers, Bank, Location, Unit, User, Installer, Service, Tabs and Kids; missing stored values default to Read.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The authenticated manager's current display values and permission summary for this site."
      },
      "ManagerResetPasswordRequest": {
        "required": [
          "confirmPassword",
          "password",
          "token"
        ],
        "type": "object",
        "properties": {
          "token": {
            "maxLength": 4096,
            "minLength": 0,
            "type": "string",
            "description": "The opaque token from the email link, submitted unchanged."
          },
          "password": {
            "maxLength": 128,
            "minLength": 12,
            "type": "string",
            "description": "12–128 printable ASCII characters; no leading/trailing spaces. Uses the existing login hash."
          },
          "confirmPassword": {
            "minLength": 1,
            "type": "string",
            "description": "A second entry of the new password, matching Password exactly."
          }
        },
        "additionalProperties": false,
        "description": "Redeems the emailed token. Never log this body or return its contents."
      },
      "ManagerResourceGrantResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "The canonical tenant, bank, or location KID, with omitted stored tenants resolved to the API site.",
            "nullable": true
          },
          "scope": {
            "type": "string",
            "description": "Tenant means all banks/locations on this site; Bank means all locations in that bank; Location means only that location. No names or business records are fetched.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A site-bound bank/location scope for the access overview."
      },
      "ManagerSessionResponse": {
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string",
            "description": "Opaque token for Authorization: Bearer {accessToken}. Do not decode it as a JWT or put it in a URL.",
            "nullable": true
          },
          "expiresIn": {
            "type": "integer",
            "description": "Lifetime in seconds.",
            "format": "int64"
          },
          "tokenType": {
            "type": "string",
            "description": "The Authorization header scheme.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A short-lived opaque API token; no refresh token is issued."
      },
      "ManagerSignUpConfirmation": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "Protected single-use mailbox proof.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Single-use mailbox proof for the pending manager."
      },
      "ManagerSignUpRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Mailbox to verify.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Manager name.",
            "nullable": true
          },
          "organisation": {
            "type": "string",
            "description": "Manager organisation.",
            "nullable": true
          },
          "password": {
            "type": "string",
            "description": "Password chosen at registration.",
            "nullable": true
          },
          "confirmPassword": {
            "type": "string",
            "description": "Matching password confirmation.",
            "nullable": true
          },
          "language": {
            "type": "string",
            "description": "Optional email language: exactly lowercase en, da or es. Omitted/null uses English; empty or other values are invalid.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Required self-registration profile with no permission selectors."
      },
      "ManagerTabChangeRequest": {
        "required": [
          "expectedRevision"
        ],
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Required boolean; true assigns the tab and false removes it.",
            "nullable": true
          },
          "expectedRevision": {
            "type": "string",
            "description": "Required opaque tabsRevision from GetManager or the latest SetManagerTab response.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Desired state of one numeric eTab grant, using the last returned Tabs revision."
      },
      "ManagerTabChangeResponse": {
        "type": "object",
        "properties": {
          "tabs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagerTabResponse"
            },
            "description": "Complete recognized selected tabs, sorted by metadata then numeric ID.",
            "nullable": true
          },
          "tabsRevision": {
            "type": "string",
            "description": "Opaque revision for the next edit, including preserved unknown numbers.",
            "nullable": true
          },
          "canEditTabs": {
            "type": "boolean",
            "description": "False if removing your own Managers1 grant removes edit access."
          },
          "canEditPermissions": {
            "type": "boolean",
            "description": "False if the same change removes your permission-editing access."
          }
        },
        "additionalProperties": false,
        "description": "The acknowledged tab selection and concurrency state."
      },
      "ManagerTabResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "The persisted eTab number.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "The shared enum member name.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity based on eTab AttributeMetaIcon, empty when absent or none. Calendar includes today's day in Text.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A permitted page's identity in the shared eTab enum."
      },
      "ManagerThemeRequest": {
        "required": [
          "themeMode"
        ],
        "type": "object",
        "properties": {
          "themeMode": {
            "$ref": "#/components/schemas/eThemeMode"
          }
        },
        "additionalProperties": false,
        "description": "Sets the caller's own appearance preference; no manager or tenant override is accepted."
      },
      "ManagerThemeResponse": {
        "type": "object",
        "properties": {
          "themeMode": {
            "$ref": "#/components/schemas/eThemeMode"
          }
        },
        "additionalProperties": false,
        "description": "The manager's successfully stored appearance preference."
      },
      "NearestLocationItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "bankName": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "distanceMeters": {
            "type": "number",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "Authorized display identity and great-circle distance in metres, without the caller's position."
      },
      "ObjectAddressResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "latitude": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "longitude": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "autoLatitudeLongitude": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "outcome": {
            "type": "string",
            "nullable": true
          },
          "canWrite": {
            "type": "boolean",
            "description": "Display hint from the current snapshot; every mutation independently reauthorizes."
          }
        },
        "additionalProperties": false,
        "description": "Current own settings, stable revision and safe operation outcome; no inherited address."
      },
      "ObjectAddressRevisionRequest": {
        "required": [
          "expectedRevision"
        ],
        "type": "object",
        "properties": {
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Revision for a deliberate coordinate lookup."
      },
      "OpeningHoursGroup": {
        "type": "object",
        "properties": {
          "units": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpeningHoursUnit"
            },
            "nullable": true
          },
          "weekly": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpeningHoursLine"
            },
            "nullable": true
          },
          "exceptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpeningHoursLine"
            },
            "nullable": true
          },
          "isOpenNow": {
            "type": "boolean",
            "nullable": true
          },
          "nextChange": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Units sharing the same effective weekly plan and upcoming exceptions."
      },
      "OpeningHoursLine": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "opens": {
            "type": "string",
            "nullable": true
          },
          "closes": {
            "type": "string",
            "nullable": true
          },
          "closesNextDay": {
            "type": "boolean"
          },
          "daysOfWeek": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Open, Closed, AllDay or Unknown; times are local HH:mm, with an explicit overnight flag."
      },
      "OpeningHoursUnit": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An authorized unit identity and localized display name."
      },
      "PeopleDirectoryCount": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authorized count and red badge icon; each operation documents its cache age and precision."
      },
      "PersonalAccountResult": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stable success/error code, containing no secrets."
      },
      "PersonalApiKeyRequest": {
        "required": [
          "revision"
        ],
        "type": "object",
        "properties": {
          "revision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Generate a replacement against the last acknowledged API-key revision."
      },
      "PersonalApiKeyResponse": {
        "type": "object",
        "properties": {
          "apiKey": {
            "type": "string",
            "nullable": true
          },
          "details": {
            "$ref": "#/components/schemas/PersonalManagerApiKey"
          }
        },
        "additionalProperties": false,
        "description": "One-time plaintext key returned only after the hash was committed. Never log this response."
      },
      "PersonalEmailConfirmation": {
        "required": [
          "token"
        ],
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The single-use proof from the new mailbox."
      },
      "PersonalEmailRequest": {
        "required": [
          "currentPassword",
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "nullable": true
          },
          "currentPassword": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "New address and reauthentication, without a caller-selected manager or return URL."
      },
      "PersonalManagerApiKey": {
        "type": "object",
        "properties": {
          "hasApiKey": {
            "type": "boolean"
          },
          "revision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Own API-key status; never contains the hash or plaintext key."
      },
      "PersonalManagerProfile": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "organisation": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "emailVerified": {
            "type": "boolean"
          },
          "themeMode": {
            "$ref": "#/components/schemas/eThemeMode"
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "retentionDays": {
            "type": "integer",
            "format": "int32"
          },
          "iconSet": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Personal preferences; no credentials, administrative grants or internal verification proofs."
      },
      "PersonalManagerTab": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A stable numeric tab identity and its enum-derived name."
      },
      "PersonalManagerTabs": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "tabs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PersonalManagerTab"
            },
            "nullable": true
          },
          "availableTabs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PersonalManagerTab"
            },
            "nullable": true
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "canEdit": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Own tab selection and the finite enum catalog. CanEdit requires an explicit site-wide KID grant."
      },
      "PersonalPasswordRequest": {
        "required": [
          "confirmPassword",
          "currentPassword",
          "password"
        ],
        "type": "object",
        "properties": {
          "currentPassword": {
            "type": "string",
            "nullable": true
          },
          "password": {
            "type": "string",
            "nullable": true
          },
          "confirmPassword": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Reauthentication and matching new password entries."
      },
      "PersonalProfileRequest": {
        "required": [
          "revision",
          "value"
        ],
        "type": "object",
        "properties": {
          "revision": {
            "type": "string",
            "nullable": true
          },
          "value": { }
        },
        "additionalProperties": false,
        "description": "One personal preference with the last acknowledged profile revision."
      },
      "PersonalTabRequest": {
        "required": [
          "enabled",
          "revision"
        ],
        "type": "object",
        "properties": {
          "revision": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "One own-tab toggle; the authenticated session is the sole target."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "SearchResult": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "matchedSetting": {
            "type": "string",
            "nullable": true
          },
          "matchedValue": {
            "type": "string",
            "nullable": true
          },
          "isContext": {
            "type": "boolean"
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Mixed-result shape; kind is an enum-derived type and Kid is the sole object identifier."
      },
      "SearchResults": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchResult"
            },
            "nullable": true
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "A bounded provider result; merge by canonical Kid."
      },
      "ServiceApiKeyRequest": {
        "required": [
          "expectedRevision"
        ],
        "type": "object",
        "properties": {
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Rotate the service key only if the profile still matches the revision last read."
      },
      "ServiceApiKeyResponse": {
        "type": "object",
        "properties": {
          "apiKey": {
            "type": "string",
            "nullable": true
          },
          "details": {
            "$ref": "#/components/schemas/ServiceDetailsResponse"
          }
        },
        "additionalProperties": false,
        "description": "ApiKey is returned only by the successful generation response. Do not log or persist this response.\r\n            Details contains the committed hash and next profile revision, never another copy of the plaintext key."
      },
      "ServiceDetailsResponse": {
        "type": "object",
        "properties": {
          "service": {
            "$ref": "#/components/schemas/ServiceDirectoryItem"
          },
          "hasApiKeyHash": {
            "type": "boolean"
          },
          "apiKeyHash": {
            "type": "string",
            "nullable": true
          },
          "canEdit": {
            "type": "boolean"
          },
          "profileRevision": {
            "type": "string",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "ApiKeyHash is the hash stored in eSetting.ApiKeyHash (or an existing legacy Password-only service record) and is included only for callers with Service Write.\r\n            The published JSON names are preserved; this is never a plaintext API key.\r\n            CanEdit is only a display hint; every mutation independently reauthorizes."
      },
      "ServiceDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "identity": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconName": {
            "type": "string",
            "description": "Exact enum setting for the icon picker and Icon writes; use IconKid for images.",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Canonical bank-zero, manager-shaped KID, eUserId.ToString() identity and tenant-specific Name/Icon."
      },
      "ServiceDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceDirectoryItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The finite catalog of concrete service enum identities; never contains key hashes. NextCursor is always null."
      },
      "ServiceProfileRequest": {
        "required": [
          "expectedRevision",
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "nullable": true
          },
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Exact Name or Icon value plus the revision returned by GetService. Credentials cannot be edited manually."
      },
      "SetObjectCoordinateProvenanceRequest": {
        "required": [
          "expectedRevision",
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "type": "integer",
            "format": "int32"
          },
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One recognized coordinate provenance value and the current object revision."
      },
      "SetObjectCoordinatesRequest": {
        "required": [
          "expectedRevision",
          "latitude",
          "longitude"
        ],
        "type": "object",
        "properties": {
          "latitude": {
            "type": "integer",
            "format": "int64"
          },
          "longitude": {
            "type": "integer",
            "format": "int64"
          },
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Manual coordinates in integer millionths of degrees."
      },
      "SettlementDetailResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical bank KID.",
            "nullable": true
          },
          "period": {
            "type": "integer",
            "description": "Period number; zero is provisional.",
            "format": "int32"
          },
          "sourceEntries": {
            "type": "integer",
            "description": "Number of source entries before export exclusions.",
            "format": "int32"
          },
          "includedEntries": {
            "type": "integer",
            "description": "Number after export exclusions.",
            "format": "int32"
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SettlementGroupResponse"
            },
            "description": "Totals separated by export group and currency.",
            "nullable": true
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Supported case-sensitive format identifiers.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Reconciled totals and supported formats for a closed settlement period."
      },
      "SettlementGroupResponse": {
        "type": "object",
        "properties": {
          "group": {
            "type": "string",
            "description": "Stable export group identifier.",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "description": "Currency code.",
            "nullable": true
          },
          "entries": {
            "type": "integer",
            "description": "Included entry count.",
            "format": "int32"
          },
          "amountMinor": {
            "type": "integer",
            "description": "Signed sum in minor units.",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "One export group in one currency; amounts keep their database sign."
      },
      "SettlementHistoryResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical bank KID.",
            "nullable": true
          },
          "nextSettlement": {
            "type": "string",
            "description": "Next scheduled close in UTC; null when unknown.",
            "format": "date-time",
            "nullable": true
          },
          "periods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SettlementPeriodResponse"
            },
            "description": "Closed period metadata, newest first.",
            "nullable": true
          },
          "nextBeforePeriod": {
            "type": "integer",
            "description": "Pass as beforePeriod for older rows; null at the end.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bank settlement metadata, independent of display language."
      },
      "SettlementPeriodResponse": {
        "type": "object",
        "properties": {
          "period": {
            "type": "integer",
            "description": "Settlement period number; zero is never returned as a closed period.",
            "format": "int32"
          },
          "settlementDate": {
            "type": "string",
            "description": "Period end in UTC.",
            "format": "date-time",
            "nullable": true
          },
          "settlementRun": {
            "type": "string",
            "description": "Recorded execution time in UTC.",
            "format": "date-time",
            "nullable": true
          },
          "firstTransaction": {
            "type": "string",
            "description": "First recorded transaction time in UTC.",
            "format": "date-time",
            "nullable": true
          },
          "lastTransaction": {
            "type": "string",
            "description": "Last recorded transaction time in UTC.",
            "format": "date-time",
            "nullable": true
          },
          "amountMinor": {
            "type": "integer",
            "description": "Signed stored total in minor units, with no implied currency or export filtering.",
            "format": "int64",
            "nullable": true
          },
          "transactionCount": {
            "type": "integer",
            "description": "Stored transaction count.",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Historical metadata from LogA; missing values are null."
      },
      "TenantStatusItem": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "nullable": true
          },
          "kid": {
            "type": "string",
            "nullable": true
          },
          "bankKid": {
            "type": "string",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "bankName": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          },
          "computerName": {
            "type": "string",
            "nullable": true
          },
          "bankType": {
            "type": "string",
            "nullable": true
          },
          "unitType": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "errorId": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "timestampUtc": {
            "type": "string",
            "format": "date-time"
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "bankIconKid": {
            "type": "string",
            "description": "API-computed bank icon; use unchanged in the selected icon set's image URL.",
            "nullable": true
          },
          "locationIconKid": {
            "type": "string",
            "description": "API-computed location icon including its location number in Kid.Text.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One alert with canonical object KIDs and a UTC last-contact or out-of-order timestamp."
      },
      "TenantStatusPageResponse": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/TenantStatusResponse"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "previousCursor": {
            "type": "string",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One lazy-loaded page from a bounded, authorized status snapshot."
      },
      "TenantStatusResponse": {
        "type": "object",
        "properties": {
          "measuredAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "refreshAfterSeconds": {
            "type": "integer",
            "format": "int32"
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TenantStatusSourceResult"
            },
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TenantStatusItem"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A bounded operational snapshot; failed sources are explicit, never reported as healthy."
      },
      "TenantStatusSourceResult": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "nullable": true
          },
          "count": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          },
          "errorCode": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Outcome of one independently executed lookup. HasMore means the per-source limit was reached."
      },
      "ToolKidField": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Exact Kid property name, independent of display language.",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "Exact invariant numeric value or decoded text; numbers remain strings to avoid JavaScript precision loss.",
            "nullable": true
          },
          "enumName": {
            "type": "string",
            "description": "The actual enum ToString() name, or null when the enum value has no name.",
            "nullable": true
          },
          "enumNumber": {
            "type": "string",
            "description": "Exact enum numeric value as a string; null for properties that are not enums.",
            "nullable": true
          },
          "index": {
            "type": "integer",
            "description": "Zero-based original list position for Settings and Icons, otherwise null.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One nondefault, nonzero data property returned by the installed Flex KID parser."
      },
      "ToolKidInspectionRequest": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "A Flex KID in a representation accepted by the installed Kid parser, up to 2048 characters.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Input to the KID inspection tool. Parsing never resolves resources or grants access."
      },
      "ToolKidInspectionResponse": {
        "type": "object",
        "properties": {
          "canonicalKid": {
            "type": "string",
            "description": "The installed parser's ToString() output.",
            "nullable": true
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ToolKidField"
            },
            "description": "Nondefault, nonzero properties, with all nonzero Settings and Icons preserved in their original order.",
            "nullable": true
          },
          "normalized": {
            "type": "boolean",
            "description": "True when the installed parser reserialized the input differently, including ignored input or whitespace."
          }
        },
        "additionalProperties": false,
        "description": "Parsed KID data only, without database lookups, inferred scope, or derived display identities."
      },
      "ToolTimeOffsetChoice": {
        "type": "object",
        "properties": {
          "offset": {
            "type": "string",
            "nullable": true
          },
          "utc": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One possible offset for a local time repeated at the end of daylight saving time."
      },
      "ToolTimeRequest": {
        "type": "object",
        "properties": {
          "format": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "string",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "offset": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Pure conversion input. Format is ms2000, mi2000, ss2000, utc or local; all numbers travel as strings."
      },
      "ToolTimeResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "result": {
            "$ref": "#/components/schemas/ToolTimeResult"
          },
          "offsetChoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ToolTimeOffsetChoice"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A validation outcome, or one instant expressed in all supported reversible formats."
      },
      "ToolTimeResult": {
        "type": "object",
        "properties": {
          "ms2000": {
            "type": "string",
            "nullable": true
          },
          "mi2000": {
            "type": "string",
            "nullable": true
          },
          "ss2000": {
            "type": "string",
            "nullable": true
          },
          "utc": {
            "type": "string",
            "nullable": true
          },
          "local": {
            "type": "string",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "nullable": true
          },
          "offset": {
            "type": "string",
            "nullable": true
          },
          "dateInputRounded": {
            "type": "boolean"
          },
          "millisecondRemainder": {
            "type": "string",
            "nullable": true
          },
          "secondRemainder": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "MS2000 preserves input milliseconds. Date input follows Kombine.Flex.Time's two-millisecond truncation;\r\nDateInputRounded reports any lost ticks. MI2000 and SS2000 are null outside their reversible Int32 range.\r\nMillisecondRemainder is the part lost by SS2000; SecondRemainder is the seconds lost by MI2000.\r\nLocal is an offset-free ISO wall time in the explicitly supplied IANA TimeZone; Offset identifies the instant."
      },
      "UnitDetailsResponse": {
        "type": "object",
        "properties": {
          "location": {
            "$ref": "#/components/schemas/BankLocationResponse"
          },
          "unit": {
            "$ref": "#/components/schemas/UnitOverviewResponse"
          },
          "descriptorAvailable": {
            "type": "boolean"
          },
          "settingGroups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "stateGroups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authorized unit with the declared groups for its resolved type. No setting/state values or write permissions are returned."
      },
      "UnitDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "bankKid": {
            "type": "string",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "bankName": {
            "type": "string",
            "nullable": true
          },
          "bankIconKid": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "locationIconKid": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          },
          "deleted": {
            "type": "boolean",
            "nullable": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "unitType": {
            "type": "string",
            "nullable": true
          },
          "washDocId": {
            "type": "string",
            "nullable": true
          },
          "outOfOrder": {
            "type": "string",
            "nullable": true
          },
          "latitude": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "errorUnit": {
            "type": "string",
            "description": "Last stored eState.ErrorUnit JSON text; null unless selected, empty when absent. May describe a historical fault.",
            "nullable": true
          },
          "autoOutOfOrder": {
            "type": "string",
            "description": "Stored AutoOutOfOrder JSON when autoOutOfOrderOnly is true; otherwise null.",
            "nullable": true
          },
          "versionMinor": {
            "type": "string",
            "description": "Requested terminal eState.VersionMinor as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "bootReason": {
            "type": "string",
            "description": "Requested terminal eState.BootReason as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "booted": {
            "type": "string",
            "description": "Requested terminal eSetting.Booted as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "firmware": {
            "type": "string",
            "description": "Requested terminal eState.Firmware as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "storageCardSerialNumber": {
            "type": "string",
            "description": "Requested terminal eState.StorageCardSerialNumber as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "page": {
            "type": "string",
            "description": "Requested terminal eState.Page as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "backLight": {
            "type": "string",
            "description": "Requested terminal eState.BackLight as decoded text; null unless selected, empty when absent.",
            "nullable": true
          },
          "terminal": {
            "$ref": "#/components/schemas/UnitTerminalResponse"
          },
          "progress": {
            "$ref": "#/components/schemas/UnitProgressResponse"
          }
        },
        "additionalProperties": false,
        "description": "Unit and parent identities, display names/icons, activation/deletion state and requested unit columns."
      },
      "UnitDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnitDirectoryItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "hasAllBanksAccess": {
            "type": "boolean"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A scoped Units1 or Terminals1 page. Identifiers are canonical KIDs; map coordinates belong to the parent location."
      },
      "UnitDocumentCount": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "through": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Distinct document count and effective inclusive UTC history bounds for the exact authorized unit."
      },
      "UnitDocumentPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankDocumentItem"
            },
            "description": "Document identities and authorized unit display metadata.",
            "nullable": true
          },
          "from": {
            "type": "string",
            "description": "Effective inclusive UTC search start.",
            "format": "date-time"
          },
          "through": {
            "type": "string",
            "description": "Effective inclusive UTC search end.",
            "format": "date-time"
          },
          "sort": {
            "type": "string",
            "description": "Effective sort field.",
            "nullable": true
          },
          "direction": {
            "type": "string",
            "description": "Effective sort direction.",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "description": "Effective offset.",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "description": "Effective page size.",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean",
            "description": "Another page existed when this query ran."
          }
        },
        "additionalProperties": false,
        "description": "One bounded, sorted document page for the exact authorized unit."
      },
      "UnitGroupFieldResponse": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "valueType": {
            "type": "string",
            "nullable": true
          },
          "scope": {
            "type": "string",
            "nullable": true
          },
          "valueStatus": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "string",
            "nullable": true
          },
          "ms2000": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "canEdit": {
            "type": "boolean"
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "required": {
            "type": "boolean"
          },
          "minimum": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "maximum": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnitSettingOption"
            },
            "nullable": true
          },
          "sync": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "changedBy": {
            "$ref": "#/components/schemas/UnitSettingEditorResponse"
          },
          "canReadHistory": {
            "type": "boolean"
          },
          "hasHistory": {
            "type": "boolean"
          },
          "valueFormat": {
            "type": "string",
            "nullable": true
          },
          "pattern": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stored current-unit value, or an explicit absence/scope/redaction status. MS2000 is the source krumb timestamp."
      },
      "UnitGroupResponse": {
        "type": "object",
        "properties": {
          "location": {
            "$ref": "#/components/schemas/BankLocationResponse"
          },
          "unit": {
            "$ref": "#/components/schemas/UnitOverviewResponse"
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "group": {
            "type": "string",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnitGroupFieldResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The authorized unit and one catalog-defined group, with read-only stored values."
      },
      "UnitIconResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "offline": {
            "type": "boolean",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Status 200 carries an icon; missing Alive is unknown, never an offline error."
      },
      "UnitIconsResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnitIconResponse"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bounded lazy icon lookup, with independent errors for inaccessible units."
      },
      "UnitOverviewResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "cycle": {
            "type": "string",
            "nullable": true
          },
          "cycleText": {
            "type": "string",
            "nullable": true
          },
          "unitType": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "unitTypeName": {
            "type": "string",
            "nullable": true
          },
          "unitTypeSource": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          },
          "progress": {
            "$ref": "#/components/schemas/UnitProgressResponse"
          },
          "terminal": {
            "$ref": "#/components/schemas/UnitTerminalResponse"
          }
        },
        "additionalProperties": false,
        "description": "Unit name and validated eIcon name, identified only by its canonical KID."
      },
      "UnitProgressResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "nullable": true
          },
          "percent": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "remainingSeconds": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "calculatedAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "API-calculated progress. Percent and remaining time are estimates, not hardware completion signals."
      },
      "UnitSettingEditorResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Display-only audit identity; does not grant directory/account access. UserId zero has no editor; unknown nonzero identities have no KID."
      },
      "UnitSettingHistoryItem": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "nullable": true
          },
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "sync": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "changedBy": {
            "$ref": "#/components/schemas/UnitSettingEditorResponse"
          }
        },
        "additionalProperties": false,
        "description": "The stored value, exact source timestamp, acknowledgement flag and editor display identity."
      },
      "UnitSettingHistoryResponse": {
        "type": "object",
        "properties": {
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "group": {
            "type": "string",
            "nullable": true
          },
          "setting": {
            "type": "string",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnitSettingHistoryItem"
            },
            "nullable": true
          },
          "nextBeforeMs2000": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "valueFormat": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A page of setting changes, newest first; an exclusive timestamp continues to older rows."
      },
      "UnitSettingOption": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "nullable": true
          },
          "label": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A selectable persisted value and its localized catalog label."
      },
      "UnitSettingRequest": {
        "required": [
          "expectedRevision",
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "nullable": true
          },
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Invariant setting text with the revision obtained from GetUnitGroup."
      },
      "UnitSettingResponse": {
        "type": "object",
        "properties": {
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "group": {
            "type": "string",
            "nullable": true
          },
          "setting": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "string",
            "nullable": true
          },
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "sync": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "changedBy": {
            "$ref": "#/components/schemas/UnitSettingEditorResponse"
          }
        },
        "additionalProperties": false,
        "description": "Confirmed stored setting and a new revision for subsequent edits."
      },
      "UnitTerminalResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed terminal icon identity, including its controller number.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Visible authorized main terminal identified by a canonical unit KID; no extra access is granted."
      },
      "UpdateObjectAddressRequest": {
        "required": [
          "address",
          "expectedRevision",
          "zip"
        ],
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "nullable": true
          },
          "zip": {
            "type": "string",
            "nullable": true
          },
          "expectedRevision": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Both address components and the last observed revision are required."
      },
      "UserActivationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "activationCode": {
            "type": "string",
            "nullable": true
          },
          "qrCodeDataV1": {
            "type": "string",
            "description": "Opaque QR payload in the existing FlexORM/FlexCipherLongs format. Empty when the tenant has no activation URL. Render the QR image in the client.",
            "nullable": true
          },
          "qrCodeDataV2": {
            "type": "string",
            "description": "Version 2: the same three values, a random 30-bit noise value, and a 30-bit checksum (0–1073741823), (((bankCode * 31 + userCode) * 31 + seconds) * 31 + noise) modulo 1073741824. Decode five values with FlexCipherLongs. Empty when the tenant has no activation URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Activation credential for an active resident; returned only to bank-wide User Create managers."
      },
      "UserAttributeInput": {
        "type": "object",
        "properties": {
          "attribute": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "Canonical eUserAttribute name and value; -1 means no numeric value."
      },
      "UserAttributeResponse": {
        "type": "object",
        "properties": {
          "attribute": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "integer",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "An eUserAttribute identifier and stored value; negative values mean no numeric value."
      },
      "UserBalanceItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "description": "Canonical resident KID.",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "ok or not-found; hidden and missing residents are indistinguishable.",
            "nullable": true
          },
          "currentBalanceMinor": {
            "type": "integer",
            "description": "Current signed balance, including discount and settlement correction.",
            "format": "int64",
            "nullable": true
          },
          "previousBalanceMinor": {
            "type": "integer",
            "description": "Latest positive period's sum, or the provisional period's corrected balance. Null when absent.",
            "format": "int64",
            "nullable": true
          },
          "previousPeriod": {
            "type": "integer",
            "description": "Resident's latest positive period, or bank's highest Log1 period plus one for a provisional period. Null when absent.",
            "format": "int32",
            "nullable": true
          },
          "previousPeriodIsProvisional": {
            "type": "boolean",
            "description": "True only for a computed, unpersisted period caused by delayed settlement. False when absent."
          },
          "latestPostingMs2000": {
            "type": "integer",
            "description": "Latest Log1 posting time across all periods and entry types, as UTC milliseconds since 2000-01-01. Zero when no postings exist; null for not-found.",
            "format": "int64",
            "nullable": true
          },
          "hasActiveSubscription": {
            "type": "boolean",
            "description": "Active card/SEPA subscription using the authorized bank's Orders state (Flags and CR2000 positive, ActionCode OK/AUTHORIZE). Null for not-found.",
            "nullable": true
          },
          "balances": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserCurrencyBalanceItem"
            },
            "description": "Separate balances by normalized Log1 currency; empty for no postings/discount or not-found. Prefer these to the legacy cross-currency scalar fields.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Signed balances in minor currency units (øre for DKK). Missing/hidden residents have status not-found and null balances."
      },
      "UserBalancesRequest": {
        "required": [
          "userKids"
        ],
        "type": "object",
        "properties": {
          "userKids": {
            "maxItems": 50,
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "One to fifty canonical resident KIDs."
          }
        },
        "additionalProperties": false,
        "description": "One to fifty canonical resident KIDs from the bank in the route. Duplicates are returned once."
      },
      "UserBalancesResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserBalanceItem"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Results in requested order, without duplicate KIDs; no results are silently truncated."
      },
      "UserCommandRequest": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "nullable": true
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "deleteAtUtc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "tagKid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "attributes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserAttributeInput"
            },
            "nullable": true
          },
          "icon": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One bounded resident command. Revision is required for existing residents; KIDs must belong to the site and bank."
      },
      "UserCurrencyBalanceItem": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "nullable": true
          },
          "currentBalanceMinor": {
            "type": "integer",
            "format": "int64"
          },
          "previousBalanceMinor": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "previousPeriod": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "previousPeriodIsProvisional": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Signed legacy minor units per currency, with no conversion. Null Currency means no stored currency code. Discount applies to DKK only."
      },
      "UserDirectoryItem": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "bankKid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "nullable": true
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Resident and parent bank identities with display metadata only."
      },
      "UserDirectoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserDirectoryItem"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          },
          "scanLimitReached": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "Authorized resident page. A short page may still have a continuation."
      },
      "UserLocationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "iconKid": {
            "type": "string",
            "description": "API-computed icon identity; use unchanged in the icon image URL.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A location KID, Access/NoAccess state and eIcon name (default house), cached up to 60 seconds. Location-scoped managers see only their locations."
      },
      "UserNumberSuggestionResponse": {
        "type": "object",
        "properties": {
          "bankKid": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Non-reserving number suggestion. Number is empty when no configured candidate is available."
      },
      "UserReceipt": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "locationKid": {
            "type": "string",
            "nullable": true
          },
          "locationName": {
            "type": "string",
            "nullable": true
          },
          "period": {
            "type": "integer",
            "format": "int32"
          },
          "provisional": {
            "type": "boolean"
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "totalMinor": {
            "type": "integer",
            "format": "int64"
          },
          "vatMinor": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "balanceAfterMinor": {
            "type": "integer",
            "format": "int64"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserReceiptLine"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One local day/location/type/period/currency group. Amounts are signed minor units."
      },
      "UserReceiptLine": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          },
          "texts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64"
          },
          "calculated": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "One decoded document; calculated adjustments have no transaction KID."
      },
      "UserReceiptsResponse": {
        "type": "object",
        "properties": {
          "userKid": {
            "type": "string",
            "nullable": true
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserReceipt"
            },
            "nullable": true
          },
          "nextOffset": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "periodCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A complete page of resident receipts. Offsets count receipts, never posting lines."
      },
      "UserScopeState": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Canonical location or tag KID with its current state."
      },
      "UserTagResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A tag KID and eTagState name."
      },
      "UserWorkspaceResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "revision": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "deletedAtUtc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "deleteAtUtc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserScopeState"
            },
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserScopeState"
            },
            "nullable": true
          },
          "attributes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserAttributeInput"
            },
            "nullable": true
          },
          "canWrite": {
            "type": "boolean"
          },
          "canCreate": {
            "type": "boolean"
          },
          "synchronization": {
            "type": "string",
            "nullable": true
          },
          "canDelete": {
            "type": "boolean"
          },
          "canRenameExternalId": {
            "type": "boolean"
          },
          "canRename": {
            "type": "boolean"
          },
          "iconKid": {
            "type": "string",
            "description": "Current display icon. New assignments must use the Person catalog.",
            "nullable": true
          },
          "availableIcons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "All Person icons, with a current non-Person icon prepended for display only.",
            "nullable": true
          },
          "canEditIcon": {
            "type": "boolean",
            "description": "Display hint: User Write and an active resident. Commands always reauthorize."
          }
        },
        "additionalProperties": false,
        "description": "Authoritative resident details and revision, with permitted operation levels and asynchronous backend synchronization."
      },
      "ValidationProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "WashDocChartDosing": {
        "type": "object",
        "properties": {
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "durationMs": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "volumeMl": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "massGrams": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "process": {
            "type": "string",
            "nullable": true
          },
          "step": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Actual SoapInfo event. Missing duration/amounts remain null; quantity is never inferred from duration."
      },
      "WashDocChartEvent": {
        "type": "object",
        "properties": {
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "label": {
            "type": "string",
            "nullable": true
          },
          "localization": {
            "type": "string",
            "nullable": true
          },
          "isCalculated": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "A stored Cycle, Process, CycleSub or Error transition. Process retains the legacy eProcess byte, independently of newer cycle enums. Stable name/value and localization key are independent of the display label."
      },
      "WashDocChartPoint": {
        "type": "object",
        "properties": {
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "value": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "isCalculated": {
            "type": "boolean"
          },
          "isEdge": {
            "type": "boolean"
          },
          "unit": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One stored timestamp. Null values break curves. Edge samples anchor drawing but are outside the visible window."
      },
      "WashDocChartResponse": {
        "type": "object",
        "properties": {
          "documentKid": {
            "type": "string",
            "nullable": true
          },
          "unitKid": {
            "type": "string",
            "nullable": true
          },
          "unitName": {
            "type": "string",
            "nullable": true
          },
          "finished": {
            "type": "boolean"
          },
          "fromMs2000": {
            "type": "integer",
            "format": "int64"
          },
          "toMs2000": {
            "type": "integer",
            "format": "int64"
          },
          "startedMs2000": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "endedMs2000": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WashDocChartSeries"
            },
            "nullable": true
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WashDocChartEvent"
            },
            "nullable": true
          },
          "signals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WashDocChartSignal"
            },
            "nullable": true
          },
          "dosing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WashDocChartDosing"
            },
            "nullable": true
          },
          "presentation": {
            "$ref": "#/components/schemas/WashDocPresentation"
          }
        },
        "additionalProperties": false,
        "description": "Renderer-independent WashDoc measurements. All times are UTC milliseconds since 2000-01-01."
      },
      "WashDocChartSeries": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "label": {
            "type": "string",
            "nullable": true
          },
          "localization": {
            "type": "string",
            "nullable": true
          },
          "group": {
            "type": "string",
            "nullable": true
          },
          "role": {
            "type": "string",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "nullable": true
          },
          "step": {
            "type": "boolean"
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WashDocChartPoint"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A sparse measurement or target series. Unit is null when not known or not uniform. Raw values are not visual band coordinates."
      },
      "WashDocChartSignal": {
        "type": "object",
        "properties": {
          "ms2000": {
            "type": "integer",
            "format": "int64"
          },
          "flags": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "heat": {
            "type": "boolean",
            "nullable": true
          },
          "inlet": {
            "type": "boolean",
            "nullable": true
          },
          "outlet": {
            "type": "boolean",
            "nullable": true
          },
          "isCalculated": {
            "type": "boolean"
          },
          "airflow": {
            "type": "boolean",
            "description": "Alliance dryer airflow switch. Null for other protocols or unknown input.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Actual InOutletHeat changes interpreted by the trusted machine profile. Null means unknown or inapplicable, never off. Holds until next stored change."
      },
      "WashDocPresentation": {
        "type": "object",
        "properties": {
          "unitType": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "nullable": true
          },
          "groupOrder": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Server-selected presentation for the original, decoded UnitType. Group order is a preference, not a measurement filter."
      },
      "eThemeMode": {
        "enum": [
          0,
          1,
          2
        ],
        "type": "integer",
        "format": "int32"
      }
    },
    "securitySchemes": {
      "ManagerBearer": {
        "type": "http",
        "description": "Paste accessToken from POST /api/v1/session/login, without the Bearer prefix. Opaque site-bound token; expires after three days. RenewManagerSession replaces an unexpired token after activity. This is not a JWT.",
        "scheme": "bearer"
      }
    }
  },
  "tags": [
    {
      "name": "Accounts"
    },
    {
      "name": "Addresses"
    },
    {
      "name": "Assistant"
    },
    {
      "name": "BankDirectory"
    },
    {
      "name": "BankDocuments"
    },
    {
      "name": "BankIcons"
    },
    {
      "name": "BankLocations"
    },
    {
      "name": "BankSearch"
    },
    {
      "name": "BankUsers"
    },
    {
      "name": "UserChanges"
    },
    {
      "name": "Bookings"
    },
    {
      "name": "Camera"
    },
    {
      "name": "Downloads"
    },
    {
      "name": "HostingLogs"
    },
    {
      "name": "HostingMetrics"
    },
    {
      "name": "InstallerIcons"
    },
    {
      "name": "Installers"
    },
    {
      "name": "LiveLogs"
    },
    {
      "name": "Locations"
    },
    {
      "name": "LocationSearch"
    },
    {
      "name": "LocationUnits"
    },
    {
      "name": "LocationWeather"
    },
    {
      "name": "ManagerCreation"
    },
    {
      "name": "Managers"
    },
    {
      "name": "ManagerInvitations"
    },
    {
      "name": "ManagerKids"
    },
    {
      "name": "ManagerPasswordRecovery"
    },
    {
      "name": "ManagerPermissionRoles"
    },
    {
      "name": "ManagerPermissions"
    },
    {
      "name": "ManagerProfiles"
    },
    {
      "name": "ManagerSession"
    },
    {
      "name": "ManagerSignUp"
    },
    {
      "name": "ManagerTabs"
    },
    {
      "name": "ManagerTheme"
    },
    {
      "name": "NearestLocations"
    },
    {
      "name": "PeopleDirectoryCounts"
    },
    {
      "name": "PersonalManager"
    },
    {
      "name": "Services"
    },
    {
      "name": "Settlements"
    },
    {
      "name": "TenantStatus"
    },
    {
      "name": "Tools"
    },
    {
      "name": "UnitDocumentList"
    },
    {
      "name": "UnitDocuments"
    },
    {
      "name": "UnitsDirectory"
    },
    {
      "name": "UnitSettings"
    },
    {
      "name": "UserBalances"
    },
    {
      "name": "UserDirectory"
    },
    {
      "name": "UserDirectoryCount"
    },
    {
      "name": "UserReceipts"
    },
    {
      "name": "UserSearch"
    }
  ]
}