{
  "openapi": "3.0.4",
  "info": {
    "title": "Kombine Flex Portal API",
    "description": "Build your own portal or agent using HTTPS and JSON. Start with LoginManager, copy accessToken into Authorize (ManagerBearer), then call GetCurrentManager. Paste the token alone; Swagger adds the Bearer prefix. Tokens are bound to the tenant hostname and deployment environment. Use api.{tenant}.kombine.technology or beta.api.{tenant}.kombine.technology; unknown hosts return HTTP 400. Select Public v1 (no login) for anonymous status, statistics and the purchase map. Authenticated operations expose your own manager profile, tabs, scopes, and operation rights. GetBankUsers provides authorized Users2 lists; GetBankLocations and GetLocationUnits provide overviews. 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. GetBankSettlements, GetBankSettlementPeriod and DownloadBankSettlement provide read-only settlement history, provisional totals and ZIP downloads. Write operations are not implemented yet. [Dansk vejledning](../docs/da) · [English guide](../docs). No API key, OAuth client registration, or special agent protocol is required.",
    "version": "v1"
  },
  "paths": {
    "/api/v1/banks/{bankKid}/locations": {
      "get": {
        "tags": [
          "BankLocations"
        ],
        "summary": "List location names, icons and canonical KIDs in bank overview order (location number).",
        "description": "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. Deleted locations follow RetentionDays; missing Deleted means zero.\n            One bank-scoped query is cached for 60 seconds. Authorization is checked on each request. No pagination or total query.\n            Locations without Name, Icon and Deleted settings are not discoverable. Missing/invalid icons use house.",
        "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/BankLocationResponse"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankLocationResponse"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankLocationResponse"
                  }
                }
              }
            }
          },
          "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": "Requires Users2 (53), User Read and a matching tenant/bank/location grant. Location-only grants\ninclude Access and NoAccess associations; other locations are removed from the response.\nOrdinary users only, including eUserId.UsersLast. Deleted users follow manager RetentionDays.\npageSize defaults to 25 (1–100). Copy previousCursor/nextCursor unchanged into cursor.\nsort: identity (legacy default, asc only), number, name, location or deleted. direction: asc or desc.\nNumber sorts numeric values before text; text comparison is ordinal case-insensitive.\nLocation uses the lowest permitted Access/NoAccess location. Missing values/not-deleted sort first in asc.\nUser identity breaks ties. Retain sort/direction with cursors; restart without cursor when changing order.\nSorted mode uses a minute-cached four-setting index and reads details for the selected page only.\nCursors are shareable positions, not credentials.\nfilter: optional case-insensitive substring in Number OR Name, at most 200 characters.\nWildcards: * matches zero or more characters; ? matches one character. Other symbols are literal.\nSurrounding whitespace is trimmed. Filtering precedes paging and uses the shared sorting index.\nKeep filter with the cursor; changing it requires starting without a cursor.\nuserKid optionally selects exactly one ordinary bank user; cannot be combined with filter or cursor.\nThe same Tab, scope, operation and retention checks apply; inaccessible/missing users return empty items.\nEach request rechecks access. Data may be cached for 60 seconds. No total count is queried.\nIn legacy identity mode at most 1,000 candidates are examined: scanLimitReached may accompany an empty/short page;\nfollow nextCursor to continue. 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"
            }
          }
        ],
        "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",
                      "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": [ ]
          }
        ]
      }
    },
    "/api/v1/locations/{locationKid}/units": {
      "get": {
        "tags": [
          "LocationUnits"
        ],
        "summary": "Get the location label and its units, ordered by unit number.",
        "description": "Requires an active manager, at least one assigned Tab, Location Read, Unit Read and matching tenant/bank/location access.\n            KID must be a canonical location KID on this site. Missing/invisible locations return 404.\n            Location and unit deletion both follow manager RetentionDays; missing Deleted means zero.\n            Current Name/Icon/Deleted settings come from Log24. Objects lacking all three cannot be discovered.\n            Missing/invalid icons use house. Unit data is cached up to 10 seconds; location labels up to 60 seconds, but authorization is reapplied on every call.\n            Unit names resolve [eLocalization numeric ID] placeholders using Accept-Language on each request (default en-GB); unknown IDs remain unchanged.\n            Cycle uses the newest MS2000 from eSetting.Cycle or eState.Cycle (state wins ties); absent/invalid values return null. Cycle is an enum name, CycleText its localized label.\n            Maximum 255 units, no paging or count query. Return empty items when the location has no visible units.",
        "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/session/login": {
      "post": {
        "tags": [
          "ManagerSession"
        ],
        "summary": "Log in with a manager email and password.",
        "description": "Send the original password over HTTPS; do not hash it in the client.\nCopy accessToken into Authorization: Bearer {accessToken} for GetCurrentManager.\nThe opaque token lasts 3,600 seconds and must not be decoded as a JWT. No refresh token is issued.\nThe API site's configuration selects the tenant, not the request.\nCredentials and current manager settings use that site's A{TenantId:D4}.Log7, BankId zero.\nTenant 166 uses A0166; there is no fallback to another tenant's manager database.\nMissing Tabs or Kids do not prevent login; inspect GetCurrentManager and explain missing access in your UI.\nIncorrect credentials return 401. After password verification, 403 codes distinguish disabled,\ndeleted, and account-settings. On 429, wait for Retry-After before another attempt.\nRejections may create an internal sanitized diagnostic record; these never expose additional account information to clients.",
        "operationId": "LoginManager",
        "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": 3600,
                  "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/me": {
      "get": {
        "tags": [
          "ManagerSession"
        ],
        "summary": "Get your profile, permitted tabs, bank/location access, and operation permissions.",
        "description": "Returns the same manager information used by the official portal's overview cards in one request.\nRights and account state are cached for at most 60 seconds per API instance; requests do not extend this.\nDo not poll continuously. Reuse the result for all cards and navigation on the current view.\nEmpty tabs means no permitted pages. hasBankAccess=false means no banks or locations on this site.\nMissing permission settings default to Read; an invalid nonempty value yields level=null and all rights false.\nOperation permissions never expand resourceGrants or tabs. No manager ID or tenant override is accepted.\nAn expired/revoked token or an inactive account returns 401; unavailable permission data returns 503.",
        "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",
                  "icon": "house",
                  "retentionDays": 30,
                  "tabs": [
                    4,
                    12
                  ],
                  "hasBankAccess": true,
                  "tabDetails": [
                    {
                      "id": 4,
                      "name": "Bank1",
                      "icon": "bank_building"
                    },
                    {
                      "id": 12,
                      "name": "Dashboard1",
                      "icon": "dashboard"
                    }
                  ],
                  "resourceGrants": [
                    {
                      "kid": "3E7Q14o2Ab",
                      "scope": "Bank"
                    }
                  ],
                  "navigationBanks": [
                    {
                      "kid": "3E7Q14o2Ab",
                      "name": "Example bank",
                      "icon": "house"
                    }
                  ],
                  "operationPermissions": [
                    {
                      "resource": "Bank",
                      "level": "Read",
                      "canRead": true,
                      "canWrite": false,
                      "canCreate": false
                    },
                    {
                      "resource": "Location",
                      "level": "Write",
                      "canRead": true,
                      "canWrite": true,
                      "canCreate": false
                    },
                    {
                      "resource": "Unit",
                      "level": "Create",
                      "canRead": true,
                      "canWrite": true,
                      "canCreate": true
                    },
                    {
                      "resource": "User",
                      "level": null,
                      "canRead": false,
                      "canWrite": false,
                      "canCreate": 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/banks/{bankKid}/settlements": {
      "get": {
        "tags": [
          "Settlements"
        ],
        "summary": "Lists 25 closed settlement periods, newest first, and the next scheduled settlement.",
        "description": "Requires Settlement2, Bank Read, User Read and access to the entire bank.\n            Location-only access cannot expose bank-wide totals. Unknown metadata is null.\n            AmountMinor is the signed stored sum, not a recalculated export total and not a currency amount.\n            Follow nextBeforePeriod to read older periods. 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": "Requires the same full-bank permissions as history. Currency groups are never merged.\n            Current user metadata is used. Period zero is provisional and may change before settlement.\n            Settlement is exempt from RetentionDays. 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/banks/{bankKid}/settlements/{period}/download": {
      "get": {
        "tags": [
          "Settlements"
        ],
        "summary": "Downloads a ZIP with one settlement file per group and currency, plus a reconciliation manifest.",
        "description": "format is case-sensitive: XLS, ATB, BL, DEAS, FRUEHØJGAARD, HEIMSTADEN, LEJERBO,\n            MD90_1, MD90_3, MD90_3_minus, MD90_3_plus, MD90_3_AABKBH or NAVISION. XLS produces real XLSX files.\n            MD90_3 supports banks 1001 and 1068 only. NIRAS and ROBERT are obsolete.\n            Invalid or oversized source data fails explicitly. This operation never closes or changes a period.",
        "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": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "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
          },
          "icon": {
            "type": "string",
            "description": "Validated eIcon name for the static icon service.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Location display metadata; KID is its sole object identifier."
      },
      "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
          },
          "icon": {
            "type": "string",
            "description": "Bank eSetting.Icon identifier, empty when absent. Never HTML or a 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
          },
          "icon": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Current user settings. Missing Deleted means not deleted; Icon is an eIcon name, default user."
      },
      "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."
      },
      "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."
      },
      "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": "Bank, Location, Unit, or User.",
            "nullable": true
          },
          "level": {
            "type": "string",
            "description": "Read, Write, Create, or null for an invalid stored value. Missing or empty settings 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."
          }
        },
        "additionalProperties": false,
        "description": "A resource category's operation level and effective cumulative rights."
      },
      "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
          },
          "icon": {
            "type": "string",
            "description": "The stored icon identifier, never executable markup or a fetched URL.",
            "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."
          },
          "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"
          },
          "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": "The four independent operation permissions; missing stored values default to Read.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The authenticated manager's current display values and permission summary for this site."
      },
      "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."
      },
      "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
          },
          "icon": {
            "type": "string",
            "description": "Icon name from eTab AttributeMetaIcon, empty when absent or none. Compiled metadata, not a database lookup.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A permitted page's identity in the shared eTab enum."
      },
      "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": { }
      },
      "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."
      },
      "UnitOverviewResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "nullable": true
          },
          "cycle": {
            "type": "string",
            "nullable": true
          },
          "cycleText": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Unit name and validated eIcon name, identified only by its canonical KID."
      },
      "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."
      },
      "UserLocationResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "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."
      },
      "UserTagResponse": {
        "type": "object",
        "properties": {
          "kid": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A tag KID and eTagState name."
      },
      "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": { }
      }
    },
    "securitySchemes": {
      "ManagerBearer": {
        "type": "http",
        "description": "Paste accessToken from POST /api/v1/session/login, without the Bearer prefix. Opaque site-bound token; expires after one hour. This is not a JWT.",
        "scheme": "bearer"
      }
    }
  },
  "tags": [
    {
      "name": "BankLocations"
    },
    {
      "name": "BankUsers"
    },
    {
      "name": "LocationUnits"
    },
    {
      "name": "ManagerSession"
    },
    {
      "name": "Settlements"
    }
  ]
}