{
  "openapi": "3.0.4",
  "info": {
    "title": "Kombine Flex Portal API",
    "description": "Build your own portal or agent using **HTTPS and JSON**.\n\n### Get started\n\n1. Call `LoginManager` with your manager credentials.\n2. Copy `accessToken` into **Authorize → ManagerBearer**. Paste only the token; Swagger adds the `Bearer` prefix.\n3. Call `GetCurrentManager` to read your profile, tabs, scopes and operation rights.\n\nNo API key, OAuth client registration or special agent protocol is required.\n\n### Tenant and language\n\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.\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.\n- **Anonymous access:** select **Public v1 (no login)** above for status, statistics, the purchase map and icon images rendered from local assets.\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.\n\n### Available operations\n\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. Requires Service Read and tenant-wide access; editing/generation also requires Service Write. Key generation does not issue bearer tokens.\n\n| Area | Operations and access |\n| --- | --- |\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). |\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). |\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). |\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. |\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. |\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. |\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). |\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. |\n| Settlements | `GetBankSettlements`, `GetBankSettlementPeriod` and `DownloadBankSettlement` provide read-only history, provisional totals and ZIP downloads. |\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). |\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). |\n| Reservations | `GetBankBookings` and `ExecuteBankBookingCommand` support Bookings1 lists, cancellation and restoration. Commands require Unit Write; event KIDs supply concurrency checks. |\n| Consumption | `GetBankAccount` and `ExportBankAccount` honor location grants. `ReverseBankAccountEntry` requires bank-wide scope and Bank/User Write. |\n\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.\n\n**Integration guides:** [English](../docs) · [Dansk](../docs/da) · [Español](../docs/es)",
    "version": "v1"
  },
  "paths": {
    "/api/v1/banks/{bankKid}/account": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "summary": "Lists Account2 postings with full-selection totals per currency.",
        "description": "### Access\n            \n- Requires **Account2** and **Bank, Location, Unit and User Read**.\n- Location grants limit the rows, totals and available filter choices.\n- No business data is read when access is denied.\n            \n### Filters and paging\n            \n- Defaults to **today** in `Europe/Copenhagen`. Both dates are inclusive; the maximum interval is **367 days**.\n- An explicit `period` replaces the date filter.\n- Sorted newest first, then by location and unit.\n- `offset`: **0–100,000**. `limit`: **1–200**, default **50**. Responses are not cached.\n            \n### Settlement periods\n            \n- The latest **100 closed period IDs** come from bank-level **LogA**.\n- With location-limited access, each offered period must also contain an authorized **Log1** posting.\n- Period **0** remains explicitly selectable. Any nonnegative period can be requested explicitly.\n            \n### Amounts and timestamps\n            \n- `amountMinor` preserves the signed Log1 amount. Totals describe **filtered movements**, not an account balance.\n- `MS2000` / `recordedAtUtc` is the event time, not an insertion watermark. Older postings may arrive days later.\n            \n### Receipts and retention\n            \n- `documents` groups this page only; merge further pages by `documentKey`. `items`, offsets and limits remain posting-based.\n- Positive DocId groups stay within the same resident, location and period. Missing/invalid IDs and payment-managed lines remain standalone.\n- `LawAccountingYears` and `LawSurveillanceDays` come from tenant Log24 with positive manager Log7 overrides.\n- Expired identities become the GDPR user KID with empty names/numbers, safe description and `isAnonymized=true`.\n- An explicit `userKid` excludes expired entries. Amounts remain in unfiltered bank totals. Zero/missing retention means no identity retention.\n- `paymentKind` is Credit, ReserveRefund or Managed, or empty. Payment identifiers are never returned.\n- Payment-managed and expired entries cannot use ordinary reversal. No external payment workflow is invoked.\n            \n### Revisions and refresh\n            \n- `revision` fingerprints the complete filtered posting set: identities, periods and monetary totals. It is independent of `offset` and `limit`.\n- **Compare revisions across pages.** If they differ, discard the accumulated pages and reload them.\n- Use `GetBankAccountRevision` for lightweight polling.\n- A revision is not a cursor, authorization token or frozen snapshot. Display labels may change independently.\n            \n### Errors\n            \n**HTTP 403** keeps code `forbidden`. After tab/resource authorization, the optional `reason` identifies a missing Read permission:\n`missing-bank-read`, `missing-location-read`, `missing-unit-read` or `missing-user-read`.\n            \n**HTTP 503** uses these codes:\n            \n- `periods-timeout`: period SQL exceeded its **10-second** limit.\n- `storage-timeout`: another SQL command timed out.\n- `storage-text-comparison`: a collation error occurred.\n            \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\n            \n- Uses the same filters and permissions as `GetBankAccount`. Paging does not affect the revision.\n- Runs **one Log1 aggregate**, plus bounded retention-setting reads, without posting rows or label lookups.\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.\n            \n### Polling and refresh\n            \n- Poll no faster than **every 30 seconds**, while the view is visible.\n- When the revision changes, reload loaded pages from offset zero. Combine only pages with equal revisions.\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\n            \n- Requires **Account2**, a **bank-wide grant**, **Bank/User Write** and **Location/Unit Read**.\n- Supports recognized consumption with resident IDs and internal tags.\n- Payment transfers, anonymous/guest entries, monthly transfers, credits and unknown transaction types are unavailable.\n- No external payment provider is called.\n            \n### Transaction and delivery\n            \n- An InnoDB transaction locks and revalidates the original posting, rejects repeated reversal with **HTTP 409**, and queues `Log2 SyncUsers`.\n- The returned posting is **queued locally**; hardware delivery is not confirmed.\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.\nRequires active manager credentials, an assigned Tab (Users2 for residents), a matching resource grant,\nBank Read and the object's Read permission; Unit also requires Location Read.\nBank and User require bank-wide or tenant-wide grants. Objects and parents must exist and not be deleted.\nDisabled locations require a tenant-wide grant. No parent address is inherited.\nLatitude and longitude are nullable integer millionths of a degree; 0 is a valid coordinate.\nAutoLatitudeLongitude 1..12 is the UTC month of a successful lookup; 30 means manual.\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.\nExample: { \"address\": \"Bjerregade 5\", \"zip\": \"8722\", \"expectedRevision\": \"revision from GetObjectAddress\" }.\nAddress is limited to 512 characters, zip to 64; both strings are required and may be empty to clear them.\nTrims outer whitespace. Unchanged inputs do not call Google. An incomplete address skips coordinate lookup.\nBare zip triggers one postal-city lookup for the trusted site's tenant, also in manual mode:\nTeam, Nortec and Electrolux use DK (four digits); Washco uses GB (full alphanumeric postcode);\nFinelec uses FI (five digits). Other tenants skip postal completion. Clients cannot select the country.\nAn exact, unambiguous result is appended to zip, for example \"7470 Karup J\"; existing city text is preserved.\nMissing, ambiguous or failed postal results retain the input. This lookup never changes manual coordinates.\nWhen the postal result lacks a city, the full address lookup may supply one with matching postal code and country.\nIn manual mode this fallback updates Zip only, retaining the coordinate pair and provenance.\nThere are at most two Google requests: postal completion followed by automatic coordinate lookup; neither is retried.\nExisting automatic coordinates are cleared and provenance is set to 0 before the Google request.\nSuccess inserts Latitude, Longitude and the UTC month atomically. Failure leaves automatic coordinates empty.\nManual provenance 30 preserves coordinates and skips coordinate lookup. Concurrent edits supersede the provider result.\nHTTP 200 confirms the saved state; inspect outcome for Success, Unchanged, IncompleteAddress,\nManualCoordinatesPreserved, NoResult, TransientFailure, PermanentFailure, NotConfigured or Superseded.\nStorage uses bank Log2 (Bank/Location/Unit) or Log7 (User), with Sync=0 and append-only history.\nNo automatic retries. On 409 reload. After a timeout, lost response or 503, read back before retrying:\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\" }.\nOne Google request at most. Automatic coordinates are cleared first; manual coordinates survive failure.\nFor a Location whose Address is blank, use its own Name plus Zip as the lookup input.\nOnly a successful result inserts Name into Address together with the coordinate pair and UTC month.\nName-based failures preserve the prior values; missing/invalid Name or Zip returns IncompleteAddress.\nA concurrent rename supersedes the name-based result, just like a concurrent address edit.\nA concurrent edit returns Superseded without overwriting the newer values. Outcome and errors follow UpdateObjectAddress.\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.\nExample: { \"latitude\": 55771181, \"longitude\": 9697176, \"expectedRevision\": \"current revision\" }.\nLatitude range is -90000000..90000000; longitude -180000000..180000000. Both are required.\nManual coordinates survive future address edits. LookupObjectCoordinates can deliberately replace them.\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.\nSupported values: 0 (unknown), 1..12 (successful lookup month), 13 (legacy pending), 20 (legacy failed), 30 (manual).\nValues 1..12 require an existing valid coordinate pair. Manual (30) is allowed before coordinates exist.\nSelecting 13 does not call Google or enqueue a retry.\nOnly 30 protects coordinates against automatic lookup on subsequent address changes.\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.\nWith Logz.io shipping enabled, the current question text is logged once after session revalidation,\nbefore model use. History, answers and bearer credentials are not included in this log event.\nRequires server-side configuration. The current manager session is revalidated before model use;\neach business read independently enforces its existing Tab/KID/Read permissions. No special agent rights.\nquestion: 1–2000 characters. history: at most 12 user/assistant messages, 8000 characters each,\n20000 total. History is untrusted context; no server-side conversation is retained. Accept-Language selects\nthe default answer language. Response answer is plain text. operations lists attempted business reads;\nlinks contains up to 20 bank/location links derived from successful authorized results.\nAt most 8 reads, pages capped at 50, 48000 bytes per result and 120 seconds per question.\nAvailable reads: SearchBanks, SearchLocations, SearchUsers, GetSearchBank, GetBankLocations,\nGetLocations, GetLocationUnits, GetTenantStatus. Missing access, partial sources and truncation must not\nbe interpreted as empty/healthy data. Generated answers can be wrong; verify the underlying records.\nReviewed AGENTS.md instructions and three named skills are packaged with the API. Skill loading uses\nthe same model-turn budget and grants no extra permissions. The balance skill explains that balance\nand account-transaction reads are not currently in the approved chat catalogue.\n400 invalid input; 401 invalid/revoked session; 403 session denied; 429 six questions/minute per manager\nor global capacity exhausted; 503 assistant-not-configured/provider unavailable/deadline. Assistant\nfailures have a code extension; middleware authentication, validation and throttling retain their normal\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/{bankKid}/documents": {
      "get": {
        "tags": [
          "BankDocuments"
        ],
        "summary": "Search WashDoc document identities by location, unit and time without loading measurements.",
        "description": "### Access\nActive manager bearer, at least one of WashDoc1/2/3, Location Read and Unit Read, and a matching resource grant.\nLocation-only grants and RetentionDays restrict both results and filter choices before paging. KIDs must be canonical and site-bound.\n### Filters and ordering\nOptional locationKid and unitKid must belong to the requested bank; unitKid also selects its location.\nfrom/through are inclusive ISO 8601 timestamps with an explicit UTC offset (default: last 24 hours, maximum: 31 days).\nA document matches when a tagged Cycle setting occurs inside that interval. lastActivityUtc is its latest matching Cycle timestamp,\nnot necessarily the document's start or end. Open its table for the complete interval and completion status.\nNewest matching activity first, then location/unit/document identity. limit 1–100 (default 25), offset 0–100000, hasMore indicates another page.\nNo total count or measurement queries. Live changes can shift offset pages; reset offset to refresh the list.\n### Limits and errors\nAt most 1000 visible locations, 5000 visible/discoverable units and 35000 unit-setting rows per search; narrow by location on 422.\n400 invalid filters, 401 inactive session, 403 missing access, 404 hidden/missing filter object, 422 oversized scope, 503 storage unavailable/busy.\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": "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/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,\nBank Read, Location Read, Unit Read and a matching resource grant. A location-only grant includes only that location.\nLocation and unit RetentionDays visibility applies; disabled locations require access to all banks.\nAny included Alive.Offline=1 sets offline=true and Kid.Icons[1]=eIcon.error. A nonempty set entirely\nknown Offline=0 sets offline=false and eIcon.check. Empty/incomplete status is null unless some unit is offline.\nUnits are discovered in Log24; orphan Alive rows do not contribute. No writes.\nPer-item 403/503 returns no icon/status; 400 invalid/foreign/oversized input, 401 expired session, 503 session storage failure.\nThe API returns opaque iconKid, preserving primary icon and bank number text. Use it unchanged with GetIconFromSet.\nRead visible banks only, deduplicate and refresh at most every ten seconds, pausing hidden pages.\nStatus is cached ten seconds per authorized location set, location/label metadata sixty seconds. HTTP is no-store.\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\n            \n- Requires an active manager, at least one assigned **Tab**, **Location Read** and a matching site/bank/location grant.\n- Location-only managers see only their granted locations.\n- An explicit site-wide grant lists all location states, including disabled locations and deletions outside RetentionDays.\n- Other grants require Enabled exactly 1 and deletion within **RetentionDays**. Missing Deleted means zero;\n  zero retention hides all deleted locations, and malformed/future deletions are hidden.\n            \n### Results and cache\n            \n- Returns names, icons, enabled, deleted, deletedAt and canonical KIDs in **location-number order**.\n- Enabled is true only for stored Enabled exactly 1; missing or invalid values mean false.\n- Deleted indicates a positive Deleted MS2000 value; deletedAt is its UTC timestamp (null for zero or an unrepresentable value).\n- For status display, disabled takes precedence over deleted, then active. Status never grants access.\n- Locations lacking all Name, Icon, Deleted and Enabled settings cannot be discovered. Missing or invalid icons use `house`.\n- One bank-scoped query is cached for **60 seconds**; authorization is checked on every request.\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\n            \n- Requires at least one current **Tab**, **Bank Read** and a matching grant. A location grant allows discovery of its parent bank only.\n- Only **BankId ≥ 1000** is searchable.\n- Accepts an exact canonical or readable KID. An omitted tenant is resolved from trusted site configuration; `matchedSetting` is `Kid`.\n- Cross-tenant or inaccessible identities return no results.\n            \n### Text search and results\n            \n- Searches current bank **Name** and **SettlementEmails** using literal, case-insensitive substrings.\n- `q`: **2–128 trimmed characters**. At most **50 rows**; `hasMore` asks the caller to refine the query.\n- Current Name, Icon and SettlementEmails settings come from **Log24**, supporting JSON and legacy text.\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\n            \n- Uses the same authorization as `SearchBanks`. Only bank codes for this site's tenant and granted banks match.\n- Invalid or out-of-scope codes skip the bank lookup. Missing banks return an empty list.\n- Resolves name and icon from the cached **Log24 bank catalogue**; `zip` remains empty.\n            \n### Shared activation-code rate limit\n            \n- Maximum **5 requests per 10 minutes** and **20 per hour**, per manager in this tenant API process, across tokens and IP addresses.\n- The bank, location and resident activation-code endpoints share this quota. **All attempts count**, including malformed and successful codes.\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\n            \n- Resolves one canonical bank KID on this site before opening the bank overview, including for tenant-wide managers.\n- Requires the same active session, current Tab, **Bank Read** and matching grant as `SearchBanks`.\n- Only **BankId ≥ 1000** is discoverable. A stored search result is not an access grant.\n            \n### Result\n            \n- Returns the matching bank from the scoped catalogue, or empty items when absent or inaccessible.\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": {
      "get": {
        "tags": [
          "BankUsers"
        ],
        "summary": "Read one page of users for a bank.",
        "description": "### Access and visibility\n            \n- Requires **Users2 (53)**, **User Read** and a matching tenant/bank/location grant.\n- Location-only grants include **Access** and **NoAccess** associations; other locations are removed from the response.\n- Ordinary users only, including `eUserId.UsersLast`. Deleted users follow **RetentionDays**.\n- `email` is the current Log7 `eSetting.Email` (2800), decoded from JSON or legacy plain text.\n- `sms` is the current Log7 `eSetting.SMS` number, decoded without changing its format. Missing email/SMS values are empty.\n            \n### Paging\n            \n- `pageSize`: **1–100**, default **25**. Copy `previousCursor` or `nextCursor` unchanged into `cursor`.\n- Cursors are shareable positions, not credentials.\n- Keep filters, sort and direction unchanged while using a cursor. Restart **without a cursor** when changing them.\n            \n### Ordering\n            \n- `sort`: `identity` (legacy default, ascending only), `number`, `name`, `location` or `deleted`.\n- `direction`: `asc` or `desc`. User identity breaks ties.\n- Number orders numeric values before text. Text comparison is ordinal and case-insensitive.\n- Location uses the lowest permitted Access/NoAccess location. Missing values and not-deleted users sort first in ascending order.\n- Sorted mode uses a **four-setting index cached for one minute** and reads details only for the selected page.\n            \n### Text and identity filters\n            \n- `filter`: optional case-insensitive substring in **Number OR Name**, at most **200 characters**, with surrounding whitespace trimmed.\n- Wildcards: `*` matches zero or more characters; `?` matches one. Other symbols are literal.\n- Filtering precedes paging and uses the shared sorting index.\n- `userKid` selects exactly one ordinary bank user and cannot be combined with `filter` or `cursor`.\n- The same Tab, scope, operation and retention checks apply. Missing or inaccessible users return empty items.\n            \n### Location and deletion filters\n            \n- `locationKid` filters an authorized location in the same bank, including Access and NoAccess associations.\n- `deleted`: `all` (default), `active`, `deleted` or `no-access`.\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.\n- Existing visibility and deletion retention still apply. `locationKid` remains an additional association filter.\n            \n### Cache and scan limits\n            \n- Every request rechecks access. Data may be cached for **60 seconds**. No total count is queried.\n- Legacy identity mode examines at most **1,000 candidates**. `scanLimitReached` may accompany an empty or short page; follow `nextCursor` to continue.\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\n            \n- Requires an active manager, **Users2**, **User Read**, **User Create** and a **bank-wide grant**.\n- `action` must be `create`. The canonical bank KID must belong to this site.\n- No hardware access is assigned automatically.\n            \n### Result and synchronization\n            \n- **HTTP 201:** returns authoritative resident workspace details and a revision.\n- Successful creation schedules the existing backend synchronization; it is not instant hardware confirmation.\n- Resident data and synchronization use Log tables exclusively. No notification or billing operation is executed.\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\n            \n- Requires **Bookings1**, **Location/Unit/User Read** and matching bank or location grants.\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`.\n            \n### Dates and events\n            \n- Inclusive local date range, defaulting to UTC today minus **7 days** through plus **90 days**; maximum **367 dates**.\n- Weekly positions (**0–10,079**) are returned separately, never converted to UTC. `recordedAtUtc` is the event time.\n- AUT/isy events are excluded as in Bookings1. Filters and pagination run after selecting the latest event.\n            \n### Search and paging\n            \n- Search matches stored resident name/number. Only authorized location/unit filter labels are returned.\n- `limit`: **1–200**, default **50**. `offset`: **0–100,000**.\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\n            \n- `action` is `cancel` or `restore`.\n- Requires **Bookings1**, **Location/User Read**, **Unit Write** and the event's location grant.\n- The booking KID identifies the **exact event reviewed** by the caller. Stale or repeated commands return **HTTP 409**.\n            \n### Transaction and restoration\n            \n- Current events are locked and rechecked in one **InnoDB transaction**. Do not retry automatically.\n- Restoration rejects overlapping active reservations.\n- Weekly restorations are unsupported. Active weekly schedules conservatively block restoration on their unit.\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/banks/{bankKid}/account/export": {
      "get": {
        "tags": [
          "Downloads"
        ],
        "summary": "Downloads the complete filtered selection as CSV or a genuine Excel workbook.",
        "description": "### Scope and limits\n            \n- Uses the same permissions and filters as `GetBankAccount`. Pagination is ignored.\n- Maximum **10,000 rows** and **4 million description characters**.\n- Oversized selections fail with **HTTP 413**, `data-limit`, instead of returning a truncated file.\n            \n### File contents\n            \n- Downloads CSV or a genuine Excel workbook; spreadsheet formulas are neutralized.\n- Money uses signed minor units; dates use **UTC**.\n- The same retention rules, user filtering and safe descriptions as GetBankAccount apply; column names are unchanged.\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\n            \n- Uses the same **Users2/User Read**, scope, retention and filter rules as `GetBankUsers`. Authorization is rechecked for every page.\n- `deleted` accepts `all`, `active`, `deleted` and `no-access`.\n- `no-access` excludes users with recorded Access in any manager-visible location.\n- Export is not a transactionally frozen snapshot.\n            \n### Format and limits\n            \n- **UTF-8 CSV**, semicolon delimiter, stable English column identifiers and ISO UTC dates.\n- Cells are quoted and protected against spreadsheet formulas.\n- At most **10,000 residents** and **4 MiB text**.\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\n            \n- Returns a ZIP with **one settlement file per group and currency**, plus a reconciliation manifest.\n- This operation never closes or changes a period.\n            \n### Formats\n            \nThe `format` value is **case-sensitive**:\n            \n- `XLS` — produces real **XLSX** files.\n- `ATB`, `BL`, `DEAS`, `FRUEHØJGAARD`, `HEIMSTADEN`, `LEJERBO`.\n- `MD90_1`, `MD90_3`, `MD90_3_minus`, `MD90_3_plus`, `MD90_3_AABKBH`.\n- `NAVISION`.\n            \n### Restrictions\n            \n- `MD90_3` supports banks **1001 and 1068 only**.\n- `NIRAS` and `ROBERT` are obsolete.\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\nSame authorization, selection and limits as GetUnitDocumentTable. No interpolation, rounding or caching.\n### CSV format\nUTF-8 BOM, comma delimiter, quoted cells, CRLF records, MS2000 and ISO UTC columns followed by state/setting columns.\nEmbedded quotes/newlines are escaped. Potential formulas in nonnumeric text are prefixed with an apostrophe for spreadsheet safety.\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"
            }
          }
        ],
        "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\nSame authorization, selection and limits as GetUnitDocumentTable. No interpolation or caching.\n### Workbook\nGenuine BIFF8 XLS; one Document worksheet, fixed header row, MS2000 and UTC timestamps.\nSource values with more than 15 digits or noncanonical numeric formatting remain text, preserving their original representation.\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"
            }
          }
        ],
        "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\ncross-tenant app logs for managers with this access. Logs can contain other customers.\nenvironment: beta/production; application: portal-api/equipment-api/portal-web. No MySQL logs.\nReturns up to 100 plain-text lines, a fetchedAtUtc snapshot timestamp and a truncated flag.\nPoll at most every 10 seconds. This is a recent snapshot, not a durable or complete log history.\n400 invalid selection; 401 invalid session; 403 missing Tab, Read or tenant grant;\n503 hosting-not-configured or hosting-unavailable. Failed reads never return stale logs.\nProvider tokens, signed URLs and raw transport errors are never returned. Render lines as text.\nRuntime logs only; build, deploy, crash and database logs are not provided by this operation.\nWhen continuous forwarding is enabled on the collector host, reads use its bounded runtime buffer.\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.\nEvery request rechecks the bounded manager snapshot (at most 60 seconds old), before any metric cache hit.\nInfrastructure is shared: values cover all customers in the app, not this tenant's individual usage.\nenvironment is beta or production; application is portal-api, equipment-api, portal-web or mysql; hours is 1, 6 or 24.\nThese fixed selectors never accept tenant IDs, provider app IDs or URLs. The site owns all provider mappings.\nMetrics cpu/memory use percent; restarts use the provider's count series, not a calculated window total.\nSeries retain component/instance separation. Null samples are gaps; empty series mean no data, never zero.\nbandwidth.dateUtc is yesterday in UTC, independent of hours; bytes is an unsigned decimal string or null.\nFor mysql, metrics are cpu/memory/disk (provider cluster averages in percent) and connections (current threads,\ncount). Bandwidth is null. The same database may be shared by beta and production. No SQL is executed.\nCheck every errorCode: a partial response is HTTP 200 with hosting-source-unavailable for failed sources.\nAll sources failing returns 503 hosting-unavailable; disabled/missing configuration returns 503 hosting-not-configured.\nResults and failures are cached for 60 seconds on the API; refresh no faster than refreshAfterSeconds.\nFetchedAtUtc identifies the snapshot, not the latest sample. Sample timestamps may lag or be absent.\n400 invalid-hosting-selection; 401 revoked/invalid session; 403 missing-hosting-tab,\nmissing-managers-read or missing-tenant-access. No secrets or provider error bodies are returned.\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\n- Requires active manager, Installers1 (68), independent Installer Read and Write and whole-tenant access.\n- Rechecks the current locked manager account, credential stamp, tabs, rights and scope, and target existence\n  and caller RetentionDays, inside the write transaction. Manager Write alone grants nothing here.\n- installerKid must be canonical, from this site, with BankId=TenantId and eUserId.Installeres..InstalleresLast.\n- Send an exact eIcon name with eIconSubject.Person metadata and expectedRevision from GetInstaller.\n  Current non-Person icons may be displayed but cannot be assigned. Do not post clicks on an already selected legacy icon.\n            \n### Storage and response\n- Appends only eSetting.Icon to A{TenantId:D4}{TenantId:D5}.Log7 with the acting manager in TagId and database\n  MS2000. Verifies the trigger's A{TenantId:D4}.Log7 current value at BankId=TenantId before committing.\n- Serializable transaction; unchanged raw values add no history. No other installer settings or Alive change.\n- Update the icon and workspace only after a complete 200 response. Use its iconRevision for the next edit.\n- Directory indexes are invalidated locally even after uncertain outcomes; other instances may retain list\n  indexes for up to 60 seconds. Details are always fresh. All responses are no-store, with a 12-second deadline.\n            \n### Errors\n- 400 invalid-installer-kid/invalid-installer-icon; 401 revoked session; 403 missing-installers-tab,\n  missing-installers-read, missing-installers-write or missing-tenant-access; 404 installer-not-found.\n- 409 installer-icon-conflict: reread and review before another save. Revision covers the raw Icon value and row presence.\n- 503 installer-icon-unavailable: keep the displayed icon and reread before retrying manually. A lost response\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": {
      "get": {
        "tags": [
          "Installers"
        ],
        "summary": "List installers with locations, tags, account state and last activity.",
        "description": "### Access and storage\n            \n- Requires an active manager, Installers1 (68), PermissionInstaller2 Read and a whole-tenant KID grant.\n- Bank/location-only grants and Write without Read are insufficient. Current account, credential stamp,\n  tab, permission and tenant scope are checked on every page through the bounded 60-second snapshot.\n- Reads only A{TenantId:D4}.Log7, BankId=TenantId and eUserId.Installeres through InstalleresLast (1–999).\n  Tenant comes exclusively from trusted site configuration. Passwords and activation secrets are never selected.\n            \n### Returned data\n            \n- Object identifiers are canonical KIDs. Derive the displayed UserId from the installer KID.\n- Locations and tags use the same JSON/legacy decoding as residents. State is retained, including NoAccess\n  and locked/deleted/history tags. These are metadata, never additional permissions for the caller.\n- Disabled installers remain visible. Deleted installers follow the caller's RetentionDays; malformed/future\n  deletion values are hidden. LastActiveAt is the Alive row's MS2000 converted to UTC, never its Text value.\n- Missing/invalid Enabled and activity are null; missing Deleted is zero. Reads do not update activity.\n            \n### Paging, filtering and ordering\n            \n- pageSize is 1–100 (default 50). Follow nextCursor until null; a page may be empty due to retention.\n- filter is a literal, case-insensitive Name/Email substring, at most 128 characters. Wildcards are escaped.\n- Sorts: identity, name, email, locations, tags, deleted, enabled, lastActive; direction asc or desc.\n- Sort applies before paging. Text is ordinal case-insensitive; location/tag lists compare sorted numeric\n  IDs and then states lexicographically, not their displayed text or count. Identity breaks ties in the same direction.\n- Null values sort first ascending, last descending. Deleted sorts by timestamp, Enabled by null/false/true.\n- Identity ascending uses bounded keyset reads. Other sorts use a tenant-local index, at most 999 identities,\n  cached for 60 seconds, then fresh page details with retention reapplied. No per-installer queries.\n- Cursors are bound to caller, tenant, filter, ordering and page size. Restart without a cursor when any changes.\n  Concurrent updates are not a frozen snapshot; a removed cursor anchor requires restarting.\n            \n### Errors and limits\n            \n- 400: invalid-page, invalid-filter, invalid-sort or invalid-cursor. 401: invalid/revoked session.\n- 403: missing-installers-tab, missing-installers-read or missing-tenant-access.\n- 503 installers-unavailable: database unavailable or the 12-second deadline elapsed; no partial sorted result.\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"
            }
          }
        ],
        "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.\nThe canonical KID must use this site's tenant, BankId=TenantId, installer type and the installer UserId range.\nReturns 404 installer-not-found for absent or retention-hidden records. Disabled installers remain visible.\nAvailableIcons contains every eIcon with eIconSubject.Person metadata. A safe current non-Person icon\nappears first for display only. CanEditIcon additionally requires independent Installer Write.\nRead IconRevision before SetInstallerIcon; metadata and edit hints never grant authorization.\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\nmanager snapshot before source/cache access. No tenant, server URL or arbitrary query is accepted.\nEach server retains at most 100 sanitized events for 15 minutes in memory; restart clears history.\nApplication Information and all Warning-or-higher events are captured. This is neither Logz.io history nor a durable audit trail.\nPoll no faster than refreshAfterSeconds (3). Server errors are independent: check each errorCode.\nlive-logs-not-configured means disabled/missing settings; live-logs-unavailable means a source failed\nor its tenant/role did not match. Empty successful cards mean no recent events on that instance.\nBankId/UserIds are requested, authorized diagnostic IDs, scoped by tenantKid; no balance values appear.\n401 revoked/invalid session; 403 missing-logs-tab, missing-managers-read or missing-tenant-access;\n503 live-logs-unavailable for unavailable authorization storage. Browser responses are no-store.\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 Banks2 navigation icon.",
        "description": "Requires an active manager, Banks2 (5), Bank Read, Location Read and current site/bank/location grants.\nCounts distinct Log24 locations (BankId at least 1000) with Enabled exactly 1 and Deleted zero;\nmissing Deleted means zero, missing/invalid Enabled or malformed Deleted are excluded.\nThese state rules also apply to all-bank managers. For limited grants the parent bank must remain\nvisible under RetentionDays. No search, paging or client-selected scope is accepted.\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.\n401: invalid/revoked session. 403: missing-banks-tab, missing-bank-read, missing-location-read or missing-resource-access.\n503 locations-unavailable: storage unavailable or the 12-second deadline elapsed; retry manually. No-store.",
        "operationId": "GetActiveLocationCount",
        "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"
                }
              }
            }
          },
          "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\nRequires an active manager, Banks2 (5), Bank Read, Location Read and site/bank/location grants.\nEvery page rechecks the current bounded manager snapshot. Location-only grants never reveal sibling locations.\nReads only the site's Log24; BankId must be at least 1000. Discovery requires Name, Icon, VismaCustNo, Enabled or Deleted.\nAn explicit site-wide grant lists all states, including disabled locations and deletions outside RetentionDays.\nLimited grants require the location's Enabled value to be exactly 1 (missing/other values are hidden).\nFor limited grants, both bank and location deletion follow RetentionDays: zero or an inclusive window ending now;\nmissing Deleted means zero, malformed/future values are hidden. All filtering precedes paging.\nEnabled is true only for stored 1. Deleted is null when malformed, otherwise indicates a positive MS2000 value.\nDeletedAt is the corresponding UTC timestamp, or null for zero, invalid or unrepresentable values.\nBankKid and Kid are canonical identifiers. Missing names/VismaCustNo are empty, invalid icons use bank_building/house.\nHasAllBanksAccess indicates an explicit site-wide grant. Both activation codes require this grant;\nBankActivationCode additionally requires Bank Create and LocationActivationCode requires Location Create.\nOtherwise the code is null. A displayed code never grants API permission.\n            \n### Search, sorting and paging\npageSize: 1–100, default 50. filter: at most 128 characters, literal case/accent-insensitive substring of bank name,\nlocation name or VismaCustNo. Exact canonical/readable/site-relative bank and location KIDs are supported.\nComplete bank/location activation codes match only when the caller could view that code; bank codes include tenant,\nlocation codes use the trusted site tenant. No cross-tenant reads. Empty filter lists all accessible locations.\nsort: name (default, location name), bankName or vismaCustNo (external ID, text order);\ndirection: asc (default) or desc. MySQL utf8mb4_general_ci\nordering precedes LIMIT; numeric bank/location identities break ties in the same direction.\nFollow nextCursor until null; cursors are protected, expire after 15 minutes and are bound to tenant, manager,\nresource grants, retention, filter, enabledOnly, sort, direction and page size. Restart without a cursor when these change.\nenabledOnly: false by default. When true, exclude locations whose Enabled is not exactly 1 before paging.\nThis narrows the authorized view only; deletion/retention rules and activation-code permissions remain unchanged.\nConcurrent edits are not a frozen snapshot; renamed rows may move. No count or full catalogue is returned.\n            \n### Errors\n400: invalid-page, invalid-filter, invalid-sort, invalid-cursor. 401: invalid/revoked session.\n403: missing-banks-tab, missing-bank-read, missing-location-read, missing-resource-access.\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
            }
          }
        ],
        "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/search/locations": {
      "get": {
        "tags": [
          "LocationSearch"
        ],
        "summary": "Search location Name, Bank (alternative bank name), Zip, Address, VismaCustNo and TeltonikaSMS in Log24.",
        "description": "### Access and identifiers\n            \n- Requires a current **Tab**, **Location Read**, site-bound resource grants and **RetentionDays** visibility.\n- Only **BankId ≥ 1000** is searchable.\n- Accepts exact canonical or readable KIDs. An omitted tenant comes from trusted site configuration; `matchedSetting` is `Kid`.\n- Cross-tenant or inaccessible identities return no results.\n            \n### Text search\n            \n- Searches **Name**, **Bank** (alternative bank name), **Zip**, **Address**, **VismaCustNo** and **TeltonikaSMS** in Log24.\n- Literal, case-insensitive substring matching; **2–128 trimmed characters**.\n- Returns `matchedSetting` and `matchedValue`; Name has first priority.\n- A separate **60-second cache** coalesces requests.\n            \n### Results and parent banks\n            \n- At most **50 matching locations**. `hasMore` counts locations.\n- When Bank Read is granted, includes distinct parent banks with `isContext=true`.\n- Parent bank context contains only name/icon, never contact fields.\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\n            \n- Uses the same authorization as `SearchLocations`.\n- Codes contain bank/location, not tenant; the **trusted site supplies the tenant**.\n- Invalid, missing or inaccessible locations return no items. No other tenant is queried.\n- Resolves the visible name and icon in **Log24**.\n            \n### Shared activation-code rate limit\n            \n- The bank, location and resident code endpoints share **5 calls per 10 minutes** and **20 per hour**, per manager.\n- Invalid calls count toward the quota.\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-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\nRetentionDays visibility, identical to GetLocationUnits. Authorization precedes the bounded Log24 read.\nThe trusted site selects the tenant. Only visible units may contribute settings or dependency names.\nUnits are grouped by their full calendar AND rule settings. Different policies in one calendar receive\nSettingsConflict; presentation groups do not create separate quotas. This is configuration, not a\nresident-specific permission, real-time availability check or booking validation.\n            \nResponse: locationKid, calculatedAt (UTC), groups [{name?, units [{kid,name}], rules [{code,text,warning,parts}]}].\nGroups provide the compact API presentation: identical visible rules are combined;\nshared rules appear once with common=true and localized name/help, followed by differing rules per unit group.\nEach group includes units and rules. Reservation quota scopes remain separate.\nEach optional parts array contains ordered {text,isValue} objects. Concatenating their text without separators\nreproduces the unchanged rule text. isValue identifies values that clients may emphasize. If parts is absent\nor empty, use rule.text. All text is plain text, never HTML; markup-like stored values must be escaped by clients.\nAccept-Language localizes names and text, including value placement; codes remain stable.\nCurrency comes from registered settings, never the UI language; unknown currency is explicit.\nV3 calendars are supported; malformed calendars return InvalidCalendar. Missing calendars are omitted,\nexcept instant reservation. Missing legacy settings use their legacy defaults; malformed values produce\nUnknownSettings. A zero week limit describes the legacy 400-day horizon; positive limits include this week.\nBefore/after/add-time default to 15 minutes; drying-room search defaults to 4320 minutes.\nNo user bookings are loaded and no reservation or maintenance action is performed.\n            \nAt most 255 units / 8192 values, eight seconds total and two concurrent settings reads. No Alive reads\nfor rule data. 400 invalid KID/site; 401 expired/inactive session; 403 missing scope/tab/read permission;\n404 missing/retention-hidden location; 503 busy/unavailable/invalid/oversized storage. Never treat 503 as\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/locations/{locationKid}/units": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Get the location label and its units, ordered by unit number.",
        "description": "### Access and visibility\n            \n- Requires an active manager, at least one assigned **Tab**, **Location Read**, **Unit Read** and matching tenant/bank/location access.\n- Send a canonical location KID on this site.\n- Location and unit deletion both follow **RetentionDays**; missing Deleted means zero.\n- Current unit settings, Cycle, Enabled, OutOfOrder, WashDocId, Connected, Started and Done come from **Log24**, in one bounded query.\n            \n### Names, icons and cycle\n            \n- Missing or invalid unit icons use `object_cube`; explicitly configured icons are preserved.\n- The API adds the unit number to `iconKid.Text`. The `g/object_cube` asset prints it on the box face.\n- Unit names resolve `[eLocalization numeric ID]` placeholders using `Accept-Language` on each request, defaulting to `en-GB`. Unknown IDs remain unchanged.\n- Cycle uses the newest MS2000 from `eSetting.Cycle` or `eState.Cycle`; state wins ties.\n- Absent or invalid cycle values return null. `cycle` is an enum name; `cycleText` is its localized label.\n- `unitType` is the effective numeric type; `unitTypeName` is the eUnitType name when defined; `unitTypeSource` identifies the source setting.\n- A present UnitType2 takes precedence, including when malformed (null type, no legacy fallback). Otherwise UnitType is decoded using FlexOrm's `(value >> 1) & 63` rule.\n- Missing/invalid types return null, never an invented Type000. Unknown numeric types are retained without claiming metadata support.\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.\n- `Estimated` is 0–99%; `Complete` is 100% only for the actual DONE phase (excluding LinkOnline). Cycle substeps are not percentages. Disabled/out-of-order/disconnected/error states suppress estimates.\n- `UnknownEndTime` covers missing/reset/invalid times, the unknown-end sentinel, mismatched sequence DocIds and fractional Connected quality. `EstimateExpired` means wait for the actual cycle; it never means complete. Both have null percentages and remaining time.\n- Enabled must be exactly 1. Connected=0 blocks estimates; missing Connected is not assumed offline. Started/Done are JSON Text values; TagId is the sequence. No user identities are read for progress.\n            \n### Results and cache\n            \n- At most **255 units**, ordered by unit number. No paging or count query.\n- No visible units returns empty items.\n- Unit data is cached for up to **10 seconds** and location labels for up to **60 seconds**. Authorization is reapplied on every call.\n            \n### Errors\n            \n- **HTTP 404:** missing or invisible location.\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\n- Requires an active manager, at least one assigned Tab, Location Read, Unit Read and a matching tenant/bank/location grant.\n- Send a canonical unit KID on this site. The unit and its parent location must be visible within RetentionDays.\n- Uses the same bounded, ten-second location snapshot as GetLocationUnits. Authorization is reapplied on every call, before metadata is exposed.\n### Result\n- Returns `location`, `unit`, `descriptorAvailable`, `settingGroups` and `stateGroups`.\n- Group identifiers are stable eSettingGroup/eStateGroup names, deduplicated and ordered by numeric enum value.\n- Metadata comes from the installed Kombine.Flex.Units descriptor packages, selected by the unit's effective type; no runtime/hardware connection is made.\n- Missing, malformed or unsupported types return descriptorAvailable=false and empty groups. No default type is substituted.\n- This read-only operation returns group metadata, not setting/state values or editing rights.\n### Errors\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.\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\n- Same active manager, Tab, location grant, Location Read, Unit Read and RetentionDays checks as GetUnitOverview.\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.\n### Values and limits\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.\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.\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.\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.\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.\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.\n- Hidden settings are omitted; credential settings are redacted and never read. Enum field/group names are stable identifiers.\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.\n### Errors\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\n- Same manager, assigned Tab, location grant, Location Read, Unit Read and RetentionDays checks as GetUnitGroup.\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.\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.\n### Paging and values\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.\n- `changedBy` is null for UserId zero; display no user icon or name in that case.\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.\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.\n- Fetch history on demand, not once per visible row. At most 16,384 characters per value; oversized/ambiguous data fails the whole page.\n### Errors\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\nmanager, assigned Tab, location scope, Location Read, Unit Read and RetentionDays visibility as GetLocationUnits.\nOnly after authorization, reads this site's Alive rows by exact bank/location (cached up to 10 seconds).\nOffline=1 sets Kid.Icons[1] to eIcon.error; Offline=0 sets it to eIcon.check.\nMissing rows, null and other Offline values retain the configured icon without a status decoration.\nUnitId text, primary icon and other presentation fields are preserved. Never infers offline from Cycle or MainId.\nReturns items with kid, opaque iconKid, nullable offline (null for missing/unknown Alive), and status.\nPer-item 403/404/503 has null iconKid/ offline; never interpret a failed lookup as online.\nInvalid/foreign/bulk input returns 400, expired sessions 401. Response is no-store. No writes.\nFetch only displayed icons, batch duplicate KIDs, poll at most every 10 seconds and pause hidden pages.\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\nTab, location scope, Location Read, Unit Read and RetentionDays visibility as GetLocationUnits.\nOnly the units returned by that authorized overview contribute; hidden units and orphan Alive rows do not.\nAny included unit with Alive.Offline=1 sets offline=true and Kid.Icons[1]=eIcon.error.\nA nonempty set whose every unit has Alive.Offline=0 sets offline=false and Kid.Icons[1]=eIcon.check.\nOtherwise offline=null: empty locations or incomplete/unknown Alive data do not claim to be online.\nMissing status never overrides a confirmed offline unit. Primary icon, LocationId text and other fields stay intact.\nItems contain kid, opaque iconKid, nullable offline and status. Per-item 403/404/503 returns no icon/status.\nInvalid/foreign/oversized input returns 400, expired sessions 401. A failed lookup never means online.\nRead only visible icons, batch/deduplicate and refresh at most every 10 seconds; pause hidden pages.\nAlive reads share the bounded ten-second cache with GetUnitIcons. HTTP is no-store. No writes.\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\nvisibility as GetLocationUnits. Authorization precedes the opening-hours read. Only visible units can own or\ninherit schedules. The tenant is selected by site configuration, never by the caller.\n            \nOne bounded Log24 read, at most 255 units / 32,768 values, an eight-second deadline and two concurrent reads.\nNo Alive reads or writes. MasterUnitId comes from Log24 states. Missing/hidden/cyclic owners yield Unknown,\nnever assumed 24/7. A known controller with no weekly limits is AllDay. Open/close fields inherit independently\nbackwards through the week; an entirely unset unit week inherits its controller's plan. Explicit unit exceptions\nremain in effect. Equal explicit times are Closed; short openings are preserved. Overnight intervals are supported.\n            \nWeekly rows use ISO weekdays 1–7. Exceptions are concrete local dates from today through two calendar months,\nincluding year boundaries. First Wednesday, configured holidays (including the legacy Great Prayer Day), then\nCustom3/Custom2/Custom1 take precedence. Custom1 wins duplicate dates; Feb 29 applies only in leap years.\nAn explicit date exception replaces overnight spill from the previous day.\n            \nStatus values: Open, Closed, AllDay, Unknown. Times are HH:mm with closesNextDay. isOpenNow is nullable;\nnextChange carries a UTC offset and is null for unknown/no transition within the next 369 days. This describes\nthe schedule only, not equipment readiness, permissions or a guarantee that the premises are accessible.\nLocation TimeZoneId/legacy TimeZone precede bank values; missing zones default to Europe/Copenhagen. Invalid\nzones return 503. DST gaps advance to the first valid minute; repeated times use first opening/last closing.\nNames and day labels use Accept-Language. calculatedAt identifies the observation; refresh on page navigation.\n            \n400 invalid KID/site; 401 expired/inactive session; 403 missing scope/tab/read permissions;\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/managers/{managerKid}/invitation": {
      "post": {
        "tags": [
          "ManagerInvitations"
        ],
        "summary": "Send an invitation allowing an existing manager to choose a password.",
        "description": "### Access and target\n- Requires an active manager, Managers1 (28), Managers Read and Write and tenant-wide access.\n- The same own-profile lock and sole active tenant-wide manager exception apply as for profile editing.\n- Current actor credentials/permissions and target visibility are rechecked under transaction locks.\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.\n### Invitation\n- HTTP 202 with code `invitation-queued` means the mail queue transaction committed; it is not a delivery receipt.\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.\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.\n- Language is en (default), da or es. Do not automatically retry an uncertain response: the mail may already be queued.\n### Errors\n- 400 invalid-manager-kid/invalid-invitation; 401 expired credentials; 403 missing rights/own-manager-permissions; 404 manager-not-found (including retention-hidden targets).\n- 409 profile-conflict: reload after a concurrent edit. 409 manager-invitation-invalid: enable the target, restore it or save a valid email first.\n- 429 invitation-rate: at most two invitations per target per 15 minutes per instance, separate from anonymous recovery. Follow Retry-After.\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": "### Access\n            \n- Requires an active manager, Managers1 (28), independent Managers Read and Write and explicit whole-tenant access.\n- Own edits require being the sole active tenant-wide manager. All checks use the locked current Log7 snapshot, as for SetManagerPermission.\n- The site supplies the tenant. Rejects foreign/noncanonical KIDs and resident, unit, tab or transaction identities.\n            \n### Selection\n            \n- Use SearchBanks and SearchLocations to discover choices; their existing Read, scope and retention checks still apply.\n- Adding a Bank grants the entire bank and replaces its narrower location entries. A Location grants only that location.\n- Adding the site's Tenant KID selects all banks and replaces all narrower grants on this site. Already covered additions are no-ops.\n- Removing a grant removes only that exact scope. Removing all-banks does not restore previously replaced narrower entries.\n- Stored site-relative grants are resolved against this site. Unrelated foreign stored entries are preserved but grant no access here.\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.\n- Kids do not grant tabs or operation flags. No account, profile, tab or permission settings are changed.\n            \n### Saving and concurrency\n            \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.\n- Update the whole Kids display only after a valid 200 response. The response returns canonical site resourceGrants and the next kidsRevision.\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.\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.\n            \n### Errors\n            \n- 400 invalid-manager-kid or invalid-kid-change: malformed/foreign identity, unsupported scope or missing/invalid boolean/revision.\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.\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.\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\n- Send the existing login email and optionally language `en`, `da` or `es`.\n- HTTP 202 with `code: accepted` is identical for unknown, ambiguous, disabled, deleted and throttled accounts.\n- The link expires after 30 minutes, is tenant/environment-bound and cannot be reused after a reset.\n- The API uses its configured PortalWeb:BaseUrl; callers cannot supply a redirect URL.\n### Temporary delivery lock\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.\n- Delivery is asynchronous through the existing Mails worker. A 202 does not guarantee delivery.\n### Errors\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\n- Send token, password and confirmPassword. Use 12–128 printable ASCII characters with no leading/trailing spaces.\n- The new password must differ from the existing password; the shared legacy password hash is retained for login compatibility.\n- HTTP 200 `code: password-reset` means Log7 and a notification mail were committed together. Sign in normally afterwards.\n- Changing the password invalidates existing manager sessions when rechecked (other API instances may cache them for up to one minute).\n### Errors\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.\n- 429 IP limit; 503 storage unavailable. Never automatically retry a reset with an uncertain outcome; try normal login or request a new link.\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 seven permission categories with a predefined administrator role.",
        "description": "### Access\n            \n- Requires an active manager, Managers1 (28), independent Managers Read and Write, and a whole-tenant KID grant.\n- Own edits require being the sole active tenant-wide manager. The same fresh transactional authorization as SetManagerPermission applies.\n            \n### Presets\n            \n| role | Bank | Location / Unit / User | Managers / Installer / Service |\n| --- | --- | --- | --- |\n| accounting (Regnskab) | Read (1) | Read (1) | None (0) |\n| caretaker (Varmemester) | Read (1) | Read + Write (3) | None (0) |\n| operator (Operatør) | All six flags (63) | All six flags (63) | All six flags (63) |\n            \n- Replaces the whole matrix, including clearing existing extra flags. Accounting also replaces Tabs with exactly Users2 (53), Account2 (2) and Settlement2 (40), removing every other ID, including unknown stored IDs. Other roles preserve Tabs.\n- Kids, account state and profile fields are unchanged.\n- A preset is a one-time assignment, not a stored or continuously enforced role. Individual checkboxes remain editable afterward if authorized.\n- Applying accounting or caretaker to yourself removes Managers access. The response sets canEditPermissions=false; disable further editing. Operator enables all 42 checkboxes and retains Managers access.\n            \n### Concurrency and storage\n            \n- Read GetManager first. Send expectedFlags for all seven categories, using explicit null for invalid stored values. Accounting additionally requires expectedTabsRevision copied from tabsRevision; older clients must send this property before applying accounting.\n- Requests must contain all seven categories, including Service. Incomplete category sets are rejected.\n- One serializable Log7 transaction validates every expected mask and the Tabs revision before writing, appends only changed settings with the caller as actor, and verifies every current-table trigger. There are no partial permission/tab updates.\n- Every role response includes tabs, tabsRevision, canEditTabs and canEditPermissions. Validate all returned permissions and tabs before changing the display; use the new tabsRevision for the next edit.\n- Update the whole display only after a valid 200 response. Session cache invalidation also applies to uncertain outcomes.\n            \n### Errors\n            \n- 400 invalid-permission-role: unknown role, missing/extra categories, invalid masks or missing/invalid expectedTabsRevision for accounting. Invalid tenant/KID returns invalid-manager-kid.\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.\n- 409 permission-conflict or tabs-conflict: reload and review; nothing is partially saved. Accounting returns invalid-stored-tabs for malformed stored JSON/non-integer tab IDs without overwriting it.\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
                }
              }
            },
            "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": "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\n            \n- Requires an active manager, **Managers1 (28)**, independent **Managers Read and Write**, and a **tenant-wide KID grant**.\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.\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.\n- The actor's current Log7 account, credential stamp and access are rechecked inside the write transaction, without the session cache.\n            \n### Request and concurrency\n            \n- `resource`: Managers, Installer, Service, Bank, Location, Unit or User. Send a canonical manager KID on this site, bank zero.\n- `flag`: one numeric bit: Read=1, Write=2, Create=4, Delete=8, RenameExtrenatId=16 or Rename=32. `enabled` is the desired boolean state.\n- `expectedFlags` is required: send the category's flags from GetManager, including null for malformed stored values.\n- **409 permission-conflict:** reload and review before retrying. Only the selected bit changes; no bit implies another.\n            \n### Storage and errors\n            \n- Appends bank-zero Log7 history with the caller as actor; verifies the current Log7 trigger before commit. No-op requests append nothing.\n- Disabled targets can be edited. Missing or retention-hidden targets return **404 manager-not-found**.\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.\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\n            \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.\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.\n            \n### Values and saving\n            \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.\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.\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.\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.\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.\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.\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.\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.\n            \n### Errors and freshness\n            \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.\n- 409 profile-conflict: reread and review before retrying. The revision covers all seven profile fields, including their raw stored forms.\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.\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": {
      "get": {
        "tags": [
          "Managers"
        ],
        "summary": "List administrators in the site's eUserId.Managers through ManagersLast range.",
        "description": "### Access\n            \n- Requires an active manager session, **Managers1 (28)**, **PermissionManagers2 Read** and an explicit **tenant-wide KID grant**.\n- Bank/location-only grants are insufficient. Write does not imply Read; missing permission values default to Read.\n- Every request checks the current bounded session snapshot, at most **60 seconds** old.\n            \n### Returned metadata\n            \n- Reads `Log7`, bank zero, without reading credentials for listed managers. Disabled managers remain listed.\n- Deleted records follow the **caller's RetentionDays**.\n- Resource grants contain only this site's valid scopes. Tab grants are metadata, not proof of effective access.\n- `operationPermissions` and `retentionDays` describe the **listed manager**, never the caller.\n- **Service** comes from `PermissionService2` (3017) and has independent flags; it does not grant login or other categories' permissions.\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.\n- Missing `Permission*2` settings default to Read; malformed settings grant nothing. Missing, invalid or negative `RetentionDays` becomes zero.\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.\n            \n### Filtering and paging\n            \n- `filter` matches a case-insensitive substring of decoded **Name OR Email** before pagination. SQL wildcard characters are literal.\n- Pagination scans at most `pageSize` candidates. A page can be short or empty while `nextCursor` is non-null; **continue until null**.\n- Changing filter, sort, direction or page size requires restarting **without a cursor**.\n- Concurrent inserts and changes are not a frozen snapshot.\n            \n### Ordering\n            \n- Selectable ordering uses a shared **seven-setting index**, cached for at most **60 seconds**, then reads fresh page details.\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.\n- Identity ascending retains its bounded database scan. All modes reapply authorization and deletion retention per page.\n- Text ordering is ordinal and case-insensitive. Kids compare sorted, site-relative numeric bank/location scopes; empty lists come first.\n- Enabled orders **missing, false, true**. Deleted orders by deletion time, zero first. Descending reverses ties as well.\n            \n### Limits and errors\n            \n- At most **20,000 matching identities** in the index. Larger selections return **HTTP 503** with `manager-directory-too-large`; narrow the filter.\n- A missing continuation identity after index refresh returns **HTTP 400**, `invalid-cursor`; restart without a cursor.\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–100, default 50. Keep unchanged 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
                        }
                      ],
                      "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}": {
      "get": {
        "tags": [
          "Managers"
        ],
        "summary": "Read one administrator by canonical manager KID for a workspace shortcut.",
        "description": "### Access and identity\n            \n- Uses the same active-session, **Managers1**, **Managers Read** and **whole-tenant grant** requirements as `GetManagers`.\n- Reads only this site's `Log7`, bank zero. A bookmark is not permission.\n            \n### Visibility and result\n            \n- Disabled administrators remain visible; deletion retention still applies.\n- **HTTP 404:** the exact manager is absent or outside retention.\n- No passwords or activation credentials are returned.\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.\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.\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.\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.\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.\n- `operationPermissions` also includes **Service**, from `PermissionService2` (3017). Its flags are independent and do not grant login or permissions in other categories.\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
                    }
                  ],
                  "resourceGrants": [
                    {
                      "kid": "A6Q14o7D0b",
                      "scope": "Bank"
                    }
                  ],
                  "tabs": [
                    {
                      "id": 28,
                      "name": "Managers1",
                      "iconKid": ""
                    }
                  ],
                  "availableTabs": [
                    {
                      "id": 5,
                      "name": "Banks2",
                      "iconKid": ""
                    },
                    {
                      "id": 60,
                      "name": "Services1",
                      "iconKid": ""
                    },
                    {
                      "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": 50,
                      "name": "Units1",
                      "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": "Disp62",
                      "iconKid": ""
                    },
                    {
                      "id": 63,
                      "name": "Disp63",
                      "iconKid": ""
                    },
                    {
                      "id": 64,
                      "name": "Disp64",
                      "iconKid": ""
                    },
                    {
                      "id": 65,
                      "name": "Disp65",
                      "iconKid": ""
                    },
                    {
                      "id": 66,
                      "name": "Disp66",
                      "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": "Disp73",
                      "iconKid": ""
                    },
                    {
                      "id": 74,
                      "name": "NayaxStreaks1",
                      "iconKid": ""
                    },
                    {
                      "id": 75,
                      "name": "WashDoc2",
                      "iconKid": ""
                    },
                    {
                      "id": 76,
                      "name": "Test1",
                      "iconKid": ""
                    },
                    {
                      "id": 77,
                      "name": "UserFinder1",
                      "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": 28,
                      "name": "Managers1",
                      "iconKid": ""
                    },
                    {
                      "id": 68,
                      "name": "Installers1",
                      "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/session/login": {
      "post": {
        "tags": [
          "ManagerSession"
        ],
        "summary": "Log in with a manager email and password.",
        "description": "### Sign in\n            \n- Send the **original password over HTTPS**; do not hash it in the client.\n- Use `accessToken` in `Authorization: Bearer {accessToken}` when calling `GetCurrentManager`.\n- The opaque token lasts **259,200 seconds (three days)**. Do not decode it as a JWT.\n- Before expiry, use `RenewManagerSession` to replace it after user activity. No separate refresh token is issued.\n            \n### Tenant and access\n            \n- The API site's configuration selects the tenant, not the request.\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.\n- Missing Tabs or Kids do not prevent login. Inspect `GetCurrentManager` and explain missing access in your UI.\n- If several managers match both email and password, the active, non-deleted manager with the newest `eSetting.Alive` krumb MS2000 wins.\n  Missing/invalid activity ranks last; equal activity (including all unknown) is resolved by the lowest UserId.\n  Login atomically clears Password on the other matching accounts; accounts with different passwords are unchanged.\n  Without an active match, no cleanup occurs. Grants are never merged. Read `GetCurrentManager` for the selected identity.\n            \n### Errors and diagnostics\n            \n- **HTTP 401:** incorrect credentials.\n- After password verification, **HTTP 403** distinguishes `disabled`, `deleted` and `account-settings`.\n- **HTTP 429:** wait for `Retry-After` before another attempt.\n- **HTTP 503:** credential storage or atomic duplicate cleanup is unavailable (also for more than 100 matching rows).\n  Do not automatically retry an uncertain cleanup result. No token is issued before cleanup commits.\n- Rejections may create sanitized internal diagnostics; these expose no additional account information to clients.\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\nstamp are revalidated through the same bounded (at most 60-second) snapshot as other operations.\nStore the returned accessToken and expiresIn in place of the old session. Ordinary API requests\ndo not extend token expiry. Renew only after user activity, not from an unattended keep-alive timer.\nExpired/revoked sessions require login (401); unavailable account storage returns 503.\nRenewal preserves local-development restrictions and grants no additional Tab/KID/operation access.\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\n            \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.\n- Empty `tabs` means no permitted pages. `hasBankAccess=false` means no banks or locations on this site.\n- `Banks2` (tab 5) is included when granted, like other recognized tabs.\n- `tabs` and `tabDetails` follow `AttributeMetaSortOrder` on `eTab`, then numeric tab ID. Missing sort metadata has order zero.\n            \n### Permissions\n            \n- Missing permission settings default to **Read**. An invalid nonempty value yields `level=null` and all rights false.\n- Operation permissions and tab ordering never expand `resourceGrants` or grant additional pages.\n- No manager ID or tenant override is accepted.\n- `operationPermissions` also includes **Service**, from `PermissionService2` (3017). Its flags are independent and do not grant login or permissions in other categories.\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.\n            \n### Caching and database indicator\n            \n- Rights and account state are cached for at most **60 seconds** per API instance. Requests do not extend this; do not poll continuously.\n- `databaseAccess` is an informational Log7 read/append check shared for **10 minutes**, or **1 minute** when unknown.\n- The indicator grants no manager rights, executes no writes and does not verify every bank, trigger or operation.\n            \n### Errors\n            \n- **HTTP 401:** expired/revoked token or inactive account.\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/managers/{managerKid}/tabs/{tabId}": {
      "post": {
        "tags": [
          "ManagerTabs"
        ],
        "summary": "Assign or remove one available eTab on an administrator.",
        "description": "### Access and choices\n            \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.\n- Own edits require the sole active tenant-wide manager exception; otherwise 403 own-manager-permissions. This is the same policy as SetManagerPermission.\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.\n- Tabs grant page access only. Kids, operation permissions and account status are unchanged.\n            \n### Saving and concurrency\n            \n- Send enabled plus the exact tabsRevision as expectedRevision. A stale revision returns 409 tabs-conflict; reread and review before trying again.\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.\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.\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.\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.\n            \n### Errors\n            \n- 400 invalid-manager-kid or invalid-tab-change covers foreign/malformed identities, unavailable IDs and missing inputs. 401 requires login.\n- 403 uses the same access codes as SetManagerPermission. 404 manager-not-found covers absent or retention-hidden targets.\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\n            \n- Send numeric `eThemeMode`: **System = 0**, **Light = 1**, **Dark = 2**.\n- Requires an active manager session and matching credential stamp on this site. No manager, KID or tenant selector is accepted.\n- This own-account preference needs no bank Tab, KID grant or resident-write permission, and grants no business access.\n            \n### Storage and refresh\n            \n- Writes require the site's configured write connection.\n- Repeating the stored value creates no additional history.\n- Success invalidates this API instance's profile cache. Other instances may take up to **60 seconds** to refresh.\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/session/me/profile": {
      "get": {
        "tags": [
          "PersonalManager"
        ],
        "summary": "Read your own personal settings and available person icons.",
        "description": "### Access and fields\n- Requires an active manager bearer session on this tenant with a current credential stamp. No Tabs, Kids or Managers Write are needed.\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.\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.\n- emailVerified is proof of this exact current email log version, not an old or manually assigned flag.\n- No target manager or tenant selector is accepted. Passwords and internal verification data are never returned.\n- Reads use the site's read connection only; no configured write connection or MySQL write privilege is required.\n### Errors\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/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.\nEach tab has its stable numeric id and enum name. CanEdit requires an explicit all-banks grant for this site's tenant.\nBank/location grants, even several covering current banks, do not qualify. No Managers tab or Managers Write is required.\nThe catalog includes unimplemented tabs; choosing one does not implement its page or grant business operations.\nReading uses the site's read connection only. CanEdit describes manager authorization; saving still requires database write access.\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.\nThe session selects the manager and tenant; request bodies cannot select another account or grant Kids/operation permissions.\nActive credentials and an explicit whole-tenant KID grant are checked again inside the serializable Log7 transaction.\nNo Managers tab or Managers Write is required. You may remove any own tab and later restore it while the all-banks grant remains.\nPreserves unrelated/unknown numeric tab values; identical selections append no history. Returns the committed selection and revision.\n400 invalid-tab-change; 401 invalid/revoked session; 403 missing-tenant-access;\n409 tabs-conflict or invalid-stored-tabs: reread before a manual retry; 503 unavailable/uncertain storage: never retry automatically.\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\n- field is the exact setting name: Name, Organisation, Icon, ThemeMode, RetentionDays or IconSet. Other settings are rejected.\n- Send value (string for display fields, integer 0–2 for ThemeMode) and revision from GetMyManagerProfile or the last successful write.\n- Name/Organisation allow up to 200 characters without controls. Icon must be in the person catalog; an existing legacy icon remains visible.\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 \"g\".\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.\n- Saves to your own Log7 history only. Administrative self-edit locks and grants are unchanged.\n### Response and errors\n- 200 returns the acknowledged profile and new revision. Repeating an identical stored value creates no history.\n- 400 invalid-profile; 401 stale/inactive session; 409 profile-conflict: reload before deciding whether to overwrite; 503 unavailable/uncertain storage.\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\n- Send email, currentPassword and optional language en/da/es. The current password is required even for a local development session.\n- 202 email-verification-queued means the mail is queued, not delivered; the existing address stays unchanged.\n- The trusted portal link expires after 30 minutes. Confirm it explicitly using ConfirmMyManagerEmail; a GET never changes an account.\n- The link is bound to this tenant/environment and the current email, password and verification log revisions. Changing any of these invalidates it.\n### Temporary delivery policy and errors\n- Verification is currently available only for exact domains nortec.dk, kombinetech.com and arendt.dk.\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.\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.\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\n- Anonymous POST accepting only token; possession authorizes only this exact verified address change. No manager or tenant selector.\n- 200 email-verified commits the email, a proof bound to its log version, and a notification to the former address together.\n- Old-address notifications follow the central development recipient policy. The new-address proof is never sent to a substitute mailbox.\n- Existing sessions keep their expiry and permissions. Sign in with the verified address next time. Password changes invalidate outstanding links.\n### Errors\n- 400 invalid-email-token for expired, used, wrong-site, stale or inactive-account proofs; 429 IP limit; 503 unavailable/uncertain storage.\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\n- Send currentPassword, password, confirmPassword and optional language en/da/es. The current password is always checked against locked current data.\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).\n- 200 password-changed commits password history and notification mail together. Discard the old token and sign in again.\n- Other API instances may cache old credentials for up to 60 seconds. The portal signs out after successful change.\n- Notification mail follows the existing development recipient policy. Never log these fields or automatically retry uncertain writes.\n### Errors\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": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "List concrete service enum identities, including services without saved settings.",
        "description": "### Access\n- Requires an active manager, Services1 (60), PermissionService2 Read and a whole-tenant KID grant.\n- Write does not imply Read. Manager permissions alone do not grant service access.\n- The bounded session snapshot is at most 60 seconds old; every request rechecks tenant, state and credential stamp.\n### Catalog and storage\n- Reads Name and Icon from this site's A{TenantId:D4}.Log7, BankId=0, in one bounded query.\n- Every concrete eUserId in the service range is included, even without Log7 settings. Range-end markers are excluded.\n- Identity is eUserId.ToString(). KIDs use the existing Manager type and bank zero, with the service ID allowlist.\n- No API-key hashes are selected or returned. An absent/unsafe icon displays the server icon.\n### Filtering and errors\n- filter matches Identity or Name as a literal ordinal case-insensitive substring, maximum 128 characters.\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.\n- 400 invalid-filter/invalid-sort; 401 revoked session; 403 missing-services-tab/read or missing-tenant-access.\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/{serviceKid}": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Read one predefined service, editable metadata and its icon catalog.",
        "description": "### Access and identity\n- Same active-manager, Services1, Service Read and tenant-wide grant as GetServices.\n- serviceKid must be a canonical bank-zero Manager KID for a concrete service enum value on this site.\n- A service exists by enum definition, including before its first settings write. No identity is allocated.\n### Editing metadata\n- CanEdit additionally requires Service Write. Only these callers receive ApiKeyHash; readers receive null and HasApiKeyHash.\n- ProfileRevision covers raw Name, Icon and Password, including row presence. It is not authorization.\n- AvailableIcons contains known eIcon names; a safe legacy current icon appears first for display only.\n- Hash values are opaque existing hashes, not plaintext keys. This operation does not implement service login.\n### Errors\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\n- Requires Services1, independent Service Read and Write, and a whole-tenant KID grant.\n- Rechecks the acting manager's current account, credential stamp, tab and scope inside the write transaction.\n- field is exactly Name or Icon. Value is a string. Name allows up to 200 non-control characters.\n- Icon must be a known selectable eIcon name. ApiKeyHash cannot be supplied or cleared manually:\n  field ApiKeyHash returns 400 invalid-service-profile, even with an empty value. Use GenerateServiceApiKey to replace the key.\n### Storage and acknowledgement\n- Appends one setting to this tenant's bank-zero Log7 history, with acting manager and database MS2000.\n- Serializable transaction; verifies the current Log7 trigger before commit. Unchanged values add no history.\n- Supply ExpectedRevision from GetService. Update UI only after the complete 200 response and use its new ProfileRevision.\n- No login, token issuance, permission grant, other service setting or Alive update is performed.\n### Errors\n- 400 invalid-service-kid/invalid-service-profile; 401/403 as GetServices, plus missing-services-write.\n- 409 service-profile-conflict: reload and review. 503 services-unavailable: outcome may be uncertain; reread before manual retry.\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\n- Requires an active manager, Services1, independent Service Read and Write and a whole-tenant KID grant.\n- ExpectedRevision must match GetService. Authorization is repeated inside the same Log7 transaction as the save.\n### Key and storage\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.\n- Uses exactly the existing manager password hashing function (HubManager.SHA512Salt compatible).\n- Only the resulting 128-character uppercase hash is stored as eSetting.Password, like manager passwords. Replaces the previous hash.\n- The response keeps its existing apiKeyHash/hasApiKeyHash names; these describe the Password value, not a separate storage field.\n- The plaintext key appears only in this successful response, alongside the committed details and next revision.\n- GetService cannot recover it. Copy it before leaving the page; never log the key or response, or store it in browser storage.\n- Does not issue bearer tokens. This is the only operation for replacing the stored API-key hash; manual profile hash writes are rejected.\n### Errors\n- 400 invalid-service-kid/invalid-service-profile; 401 revoked session; 403 missing service tab/read/write or tenant access.\n- 409 service-profile-conflict: reread and review. 503 services-unavailable: the outcome can be uncertain; no key is returned.\n- Never retry automatically. Reread before generating again after a lost response; a new generation replaces the key.\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\n            \n- Requires **Settlement2**, **Bank Read**, **User Read** and access to the **entire bank**.\n- Location-only access cannot expose bank-wide totals.\n            \n### Results and paging\n            \n- Returns **25 closed periods**, newest first, plus the next scheduled settlement.\n- Follow `nextBeforePeriod` to read older periods. Unknown metadata is null.\n- `amountMinor` is the signed stored sum, not a recalculated export total or a major-unit currency amount.\n            \n### Cache and effects\n            \n- Metadata is cached for at most **60 seconds**.\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\n            \n- Uses the same **full-bank permissions** as `GetBankSettlements`.\n- Returns grouped totals and available export formats. **Currency groups are never merged.**\n- Uses current user metadata.\n            \n### Provisional data and cache\n            \n- Period **0** is the provisional current period and may change before settlement.\n- Settlement is exempt from **RetentionDays**.\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\nsite/bank/location KID grants. Each request checks the bounded manager snapshot (at most 60 seconds old).\nNo tenant selector is accepted. Grants and RetentionDays for bank/location/unit are applied before LIMIT.\nLocations require Enabled exactly 1. Missing Deleted means zero; malformed/future deletions are hidden.\nOffline reads the site's Alive rows with UnitId=MainId, excluding Cluster Test, using last server contact:\nCash at least one hour old; other nonempty BankType at least one day old; at most 100 days old, inclusive.\nAutoOutOfOrder reads Log24 OutOfOrder with value AutoOutOfOrder; excludes StartSMS_60 and TimeSMS_61.\nUnitType2 takes precedence; otherwise the legacy packed type uses (value shifted right 1) AND 255.\nUnknown/missing types are excluded from AutoOutOfOrder. ErrorId is the positive integer Id in the state JSON.\nNames resolve localization placeholders using Accept-Language. All identities are canonical KIDs.\nbankIconKid and locationIconKid are ready-to-render bank/location icons from Log24;\nmissing/invalid settings use bank_building/house. The API adds the object number to Kid.Text.\nTimestampUtc means last contact for Offline and the OutOfOrder setting timestamp for AutoOutOfOrder.\nlimit is per source, 1–1000 (default 200). Sources hasMore explicitly reports truncation; there is no cursor.\nItems sort by timestamp descending, then kind and KID. The same unit may appear for both kinds.\nSources run concurrently on separate connections within a 12-second request deadline. A failed lookup\nhas errorCode=status-source-unavailable and no items; successful sources remain available in HTTP 200.\nIf all lookups fail, HTTP 503 tenant-status-unavailable is returned. Never interpret a partial result as healthy.\nClients must tolerate additional source kinds. Refresh after 30 seconds; no overlapping or hidden-page polling.\n400 invalid-limit; 401 invalid/revoked session; 403 missing-status-tab, missing-bank-read,\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).\nWithout cursor, reads a fresh bounded snapshot (1,000 rows per source). Sources counts describe that snapshot,\nnot just the page; hasMore still reports source truncation. Status.items contains only this page.\nCopy previousCursor/nextCursor unchanged with the same pageSize and language. Snapshots last at most two minutes\nand may be evicted earlier. Every page rechecks credentials, Tab, operations, resource scope and RetentionDays.\nCursors are manager/site/scope/language bound and never grant access. HTTP is no-store.\nFor a 30-second refresh omit cursor. Optional offset (0–1999) and anchor (Kind:Kid, at most 300 characters)\npreserve the visible position: the anchor is matched only among authorized results; otherwise offset is clamped.\nDo not combine cursor with offset/anchor. 400 invalid paging input/cursor, 409 changed cursor context,\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/documents/{documentKid}/table": {
      "get": {
        "tags": [
          "UnitDocuments"
        ],
        "summary": "Read a document's table as JSON with original values and column metadata.",
        "description": "### Access\n- Active manager bearer session; at least one of WashDoc1 (54), WashDoc3 (55), WashDoc2 (75); Location Read and Unit Read.\n- Requires a tenant/bank/location grant matching the canonical document KID. The site's tenant is fixed.\n- Location and unit deletion follow RetentionDays, including on SVG cache hits.\n### Fields and values\n- Optional `states`/`settings`: comma-separated exact enum names declared for this unit type. Omit for all permitted fields; an empty value selects none.\n- Hidden, credential, unbound and other-object fields are never read. Unknown types return 422. Invalid/unavailable fields return 400.\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.\n- `text` preserves the decoded original; `value` is a finite double when possible. No interpolation or rounding. Use text for exact large numbers.\n- `finished` requires a terminal Cycle and an InSync timestamp at least two minutes beyond the document end.\n### Limits and errors\n- One document, at most 31 days, 128 columns, 50,000 source samples and 500,000 cells. A 12-second storage deadline applies.\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.\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"
            }
          }
        ],
        "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\nSame KID, authorization, field selection and bounds as GetUnitDocumentTable. Requires a manager bearer token.\n### Output\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"
            }
          }
        ],
        "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\nSame authorization as GetUnitDocumentTable, reapplied before every cache lookup. Download with bearer authentication; this is not a public image URL.\n### Graph\nSame field selection; at most 16 numeric series, one labelled scale per series. Width is 480–2400 pixels (default 1200).\nThe SVG uses UTC timestamps, native lines and steps for enums/booleans, with no scripts, external resources or third-party SVG renderer.\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.\n### Cache\nOnly finished=true results enter the private disk cache, for at most 24 hours. In-progress data is read/rendered again.\nKeys include tenant-bound document KID, unit type/name, exact ordered field selection, width and renderer version.\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": "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/units/{unitKid}/groups/settings/{group}/{setting}": {
      "post": {
        "tags": [
          "UnitSettings"
        ],
        "summary": "Save one editable current-unit setting with revision protection.",
        "description": "### Access\n- Requires an active manager, an assigned Tab, matching location grant, Location Read, Unit Read and Unit Write.\n- Account, credential, permissions, retention and effective unit type are rechecked under database locks before writing.\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.\n### Request and result\n- Send `value` as invariant text (maximum 4096 characters) and `expectedRevision` from GetUnitGroup for this field.\n- Example: `{ \"value\": \"Washer 1\", \"expectedRevision\": \"64 hexadecimal characters\" }` for the Name setting.\n- Descriptor required/type/range/pattern/select constraints apply. Boolean values become 0/1. Empty optional values remain empty; no defaults are inserted.\n- Appends bank Log2 history with the editor's UserId and Sync=0. The Log24 projection must match before commit.\n- Returns confirmed value, source MS2000 and new revision. A successful save means storage accepted it, not that the physical unit has acknowledged it.\n### Errors\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.\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.\n            \n### Access and request\n            \n- Requires an active site-bound manager, Users2, User Read and a bank-wide resource grant.\n- Location-only grants cannot expose whole-bank balances.\n- Send canonical user KIDs, not numeric IDs or readable aliases.\n            \n### Balance calculation\n            \n- **Current:** Log1 period zero, the resident discount and FlexOrm's missing-settlement correction for non-cash banks.\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.\n- Both balances reuse one grouped ledger read. An existing resident without transactions still has their discount applied.\n            \n**Delayed settlement** produces a provisional previous period with a capped discount. This also applies to cash banks, whose current balance remains unchanged.\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.\n            \n### Currency\n            \n- Prefer the `balances` array: normalized Log1 currencies stay separate, without conversion. A null currency remains separate too.\n- The resident discount applies only to **DKK**. All currencies use the same resident previous period.\n- An absent currency in an existing previous period has a zero balance; no previous period remains null.\n- Scalar fields preserve the legacy cross-currency calculation for compatibility. Do not sum different currencies or use balances as a payment instruction.\n            \n### Posting and subscription metadata\n            \n- `latestPostingMs2000` is the latest Log1 posting across all periods and entry types, in UTC milliseconds since 2000-01-01; zero means no postings.\n- `hasActiveSubscription` reports an active card/SEPA subscription, not payment success or a collection instruction.\n- Both fields are null for missing/hidden residents and use the same authorized database snapshot as the balances.\n            \n### Missing data\n            \n- Missing or retention-hidden residents return `not-found` and null balances, never a fabricated zero.\n- No previous period: `previousBalanceMinor` and `previousPeriod` are null; `previousPeriodIsProvisional` is false.\n            \n### Limits and errors\n            \n- At most **two concurrent batches** per API process.\n- **20-second** database deadline; correction history is capped at **50,000 lines**.\n- Timeout or oversized correction: the entire request fails with **HTTP 503**. Reduce the batch instead of displaying partial balances.\n- For a lazy resident list, render the rows first, then request at most 10 residents per batch, one batch at a time.\n  The API maximum remains 50. Do not block list rendering or sum different currencies.\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/{userKid}/workspace": {
      "get": {
        "tags": [
          "UserChanges"
        ],
        "summary": "Read authoritative editing fields and an opaque concurrency revision. Bank-wide Users2/User Read required.",
        "description": "### Access\n            \n- Requires an active manager, **Users2**, **User Read** and a **bank-wide grant**.\n- Send canonical bank and resident KIDs belonging to this site and the same bank.\n            \n### Result\n            \n- Returns authoritative editing fields, permitted operation flags and an opaque concurrency `revision`.\n- Use this revision when calling `ExecuteBankUserCommand`.\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\n            \n- Requires an active manager, **Users2**, **User Read**, **User Create** and a **bank-wide grant**.\n- Send canonical bank and resident KIDs belonging to this site and the same bank.\n            \n### Result\n            \n- Returns the active resident's activation code, name and number for printing.\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\n            \n- Every command requires **Users2**, **User Read** and a **bank-wide grant**.\n- Send the `revision` returned by `GetBankUserWorkspace`.\n            \n### Required User permissions\n            \n- **Profile:** Rename / RenameExtrenatId for the changed fields.\n- **Icon / attributes:** Write.\n- **Icon:** send `action: \"icon\"`, `icon` (an exact eIcon name with eIconSubject.Person metadata) and `revision`.\n  Read `availableIcons` from GetBankUserWorkspace; an existing non-Person icon is display-only.\n  The confirmed response includes `icon`, `availableIcons`, `canEditIcon` and the new `revision`.\n  Numeric values, URLs and non-Person assignments return 400; deleted residents cannot be edited.\n- **Delete / restore:** Delete.\n- **Replace:** Delete and Create.\n- **Create / tag / location:** Create.\n            \n### Conflicts and synchronization\n            \n- **HTTP 409:** reload and review the current data before retrying.\n- Successful changes schedule existing backend synchronization, not instant hardware confirmation.\n- Resident data and synchronization use **Log tables exclusively**. No notification or billing operation is executed.\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/{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.\nThe canonical resident KID cannot select another tenant. Deleted-resident retention applies.\n            \nThe current and latest 24 stored period numbers are considered, within accounting/surveillance retention.\nPurchases, payments, discounts and calculated transfers to rent are separate groups. Zero-total\ndocuments and Month lines are omitted. Currencies are separate; no conversion takes place.\nAmounts are signed minor units: a purchase is positive, a payment/discount normally negative.\nReceipt balances exclude the unused current discount included in GetBankUserBalances.\nCalculated adjustments have no transaction KID. Missing VAT or currency is null, never assumed zero/DKK.\nOccurredAt includes the location's UTC offset; Date is its local calendar date.\n            \nFirst request: offset=0 without revision. Continue with nextOffset and the unchanged revision.\nHTTP 409 receipts-changed requires discarding older pages and restarting at offset zero.\nOffsets count entire receipt groups. No group is split between pages. No background polling is required.\n            \nEach request uses one read-only snapshot, at most 50,000 postings / 8 MiB of stored text and a\n12-second storage deadline. Only two reads run concurrently per API process. Oversized history\nreturns 503 receipts-too-large, never partial totals. Missing/hidden resident: 404 not-found.\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\n            \n- Requires **Users2**, **User Read** and site/bank/location grants.\n- Only **BankId ≥ 1000**, ordinary users and records visible under **RetentionDays**.\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`.\n- Cross-tenant or inaccessible identities return no results.\n            \n### Text matching\n            \n- Query length: **2–128 characters**, literal and case-insensitive.\n- **Number and email:** exact text.\n- **Name:** substring matching.\n- **TagId:** substring matching for positive decimal input; optional spaces are accepted.\n- Use `SearchUserSms` for the independent complete-phone-number lookup.\n            \n### KID-only lookup\n            \n- `kidOnly=true` accepts only a complete resident KID and skips ordinary text search.\n- Invalid input returns no items without business storage. Existing authorization still applies.\n            \n### Results and parent banks\n            \n- At most **50 resident matches**; up to **501 candidates** are checked.\n- `hasMore` also asks callers to refine broad queries when the candidate bound is reached.\n- `matchedSetting` and `matchedValue` explain each match.\n- When Bank Read is granted, includes distinct parent banks with `isContext=true`.\n- Limit and `hasMore` count residents. **Merge all result types by KID.**\n            \n### Deadlines and cache\n            \n- Name/Tag queries allow **10 seconds SQL** and **12 seconds including cache wait**.\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\n            \n- Uses the same authorization, retention, parent bank context and result bounds as `SearchUsers`.\n- Searches complete resident SMS numbers with **indexed exact Log7 Text matches**.\n- Accepts **8–15 digits**, spaces, hyphens, parentheses and an optional leading `+` or international `00`.\n- Danish eight-digit numbers match both with and without `45`.\n            \n### Independent lookup\n            \n- Runs independently of substring and TagId search.\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\n            \n- Uses the same permissions as `SearchUsers`.\n- Codes contain bank/user, not tenant; the **trusted site supplies the tenant**.\n- Resolves the ordinary resident's name and icon from current **Log7**.\n- Invalid, missing, deleted-outside-retention or inaccessible residents return no items.\n            \n### Shared activation-code rate limit\n            \n- All bank, location and resident code endpoints share **5 calls per 10 minutes** and **20 per hour**, per manager.\n- Invalid attempts count.\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."
      },
      "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."
      },
      "ActiveLocationCountResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64"
          },
          "iconKid": {
            "type": "string",
            "description": "Ready-to-render Banks2 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."
      },
      "AssistantLink": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "path": {
            "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."
      },
      "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."
      },
      "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."
      },
      "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."
      },
      "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": "Values are 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
          },
          "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;\n            clients can derive the display UserId from it. Missing Enabled is null. DeletedAt and LastActiveAt are UTC;\n            LastActiveAt is the Alive krumb's MS2000, not its Text. No credentials are 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.\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."
      },
      "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;\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."
      },
      "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
          },
          "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"
          }
        },
        "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."
      },
      "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."
      },
      "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
          },
          "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, invalid or negative values become zero. 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."
      },
      "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": {
        "required": [
          "email",
          "password"
        ],
        "type": "object",
        "properties": {
          "email": {
            "maxLength": 254,
            "minLength": 0,
            "type": "string",
            "description": "The manager's email address.",
            "format": "email"
          },
          "password": {
            "maxLength": 1024,
            "minLength": 0,
            "type": "string",
            "description": "The original password, normalized only by the documented legacy verifier."
          }
        },
        "additionalProperties": false,
        "description": "Credentials submitted over HTTPS; never log request bodies for this endpoint."
      },
      "ManagerOperationPermissionResponse": {
        "type": "object",
        "properties": {
          "resource": {
            "type": "string",
            "description": "Managers, Bank, Location, Unit, User, Installer or Service. 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 or operator; case-sensitive, required.",
            "nullable": true
          },
          "expectedFlags": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "format": "int32",
              "nullable": true
            },
            "description": "Exactly Managers, Installer, Service, Bank, Location, Unit and User with last displayed flags. Explicit null represents an invalid stored mask.",
            "nullable": true
          },
          "expectedTabsRevision": {
            "type": "string",
            "description": "Required for accounting: tabsRevision from GetManager or the last acknowledged edit. Other roles keep tabs unchanged.",
            "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 seven 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."
          }
        },
        "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
          },
          "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
          },
          "retentionDays": {
            "type": "integer",
            "description": "Days after deletion that an otherwise authorized bank, location, unit, user or reservation remains visible. Zero hides deleted objects; missing or 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 g; 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 and Service; 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."
      },
      "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."
      },
      "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."
      },
      "PersonalAccountResult": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stable success/error code, containing no secrets."
      },
      "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."
      },
      "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.\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.Password and is included only for callers with Service Write.\n            The published JSON names are preserved; this is never a plaintext API key.\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."
      },
      "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."
      },
      "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"
          }
        },
        "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 descriptor-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"
          }
        },
        "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
          }
        },
        "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 descriptor 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."
      },
      "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
          }
        },
        "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."
      },
      "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."
      },
      "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": { }
      },
      "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": "BankDocuments"
    },
    {
      "name": "BankIcons"
    },
    {
      "name": "BankLocations"
    },
    {
      "name": "BankSearch"
    },
    {
      "name": "BankUsers"
    },
    {
      "name": "UserChanges"
    },
    {
      "name": "Bookings"
    },
    {
      "name": "Downloads"
    },
    {
      "name": "HostingLogs"
    },
    {
      "name": "HostingMetrics"
    },
    {
      "name": "InstallerIcons"
    },
    {
      "name": "Installers"
    },
    {
      "name": "LiveLogs"
    },
    {
      "name": "Locations"
    },
    {
      "name": "LocationSearch"
    },
    {
      "name": "LocationUnits"
    },
    {
      "name": "ManagerInvitations"
    },
    {
      "name": "ManagerKids"
    },
    {
      "name": "ManagerPasswordRecovery"
    },
    {
      "name": "ManagerPermissionRoles"
    },
    {
      "name": "ManagerPermissions"
    },
    {
      "name": "ManagerProfiles"
    },
    {
      "name": "Managers"
    },
    {
      "name": "ManagerSession"
    },
    {
      "name": "ManagerTabs"
    },
    {
      "name": "ManagerTheme"
    },
    {
      "name": "PersonalManager"
    },
    {
      "name": "Services"
    },
    {
      "name": "Settlements"
    },
    {
      "name": "TenantStatus"
    },
    {
      "name": "UnitDocuments"
    },
    {
      "name": "UnitSettings"
    },
    {
      "name": "UserBalances"
    },
    {
      "name": "UserReceipts"
    },
    {
      "name": "UserSearch"
    }
  ]
}