openapi: 3.0.1
info:
  description: Accountflow's public API for external integrations.
  title: Accountflow Bridge API
  version: 1.0.0-rc1
servers:
- url: https://api.lab.accountflow.com
  description: lab
security:
- oauth2: []
tags:
- description: Exchange your API client's credentials for a bearer token. Every other
    endpoint requires one.
  name: Authentication
- description: "Bank accounts, transactions, and bank↔GL reconciliation"
  name: Bank & Reconciliation
- description: VAT filing terms and their status
  name: VAT
- description: "Chart of accounts, GL lines, and trial balances"
  name: General Ledger
- description: "Signed event notifications — poke, then fetch"
  name: Webhooks
- description: The accounting clients (companies) within your reach
  name: Companies
- description: Document metadata; binaries via signed URLs
  name: Documents
- description: "Push ledger data into a company that is managed through the API, and\
    \ follow each import to its outcome. Every import runs asynchronously: the request\
    \ is validated, accepted with 202, and executed by a job whose result lands on\
    \ the import. Push in this order: accounts, then dimensions and sub-ledgers (optional),\
    \ opening balances, general-ledger lines, open items. One import per kind and\
    \ company runs at a time."
  name: Imports
- description: The organization's users
  name: Users
- description: Access policies and their user assignments
  name: Access Management
- description: "Asynchronous work: submit via a resource endpoint, poll here"
  name: Jobs
- description: Verify your integration's credentials and scope
  name: Identity
paths:
  /protocol/openid-connect/token:
    post:
      description: |-
        Exchanges an API client's `client_id` and `client_secret` for a short-lived bearer token, using the OAuth 2.0 client-credentials grant. Send the token as `Authorization: Bearer <access_token>` on every other request.

        Create a client under organization settings → integrations; the secret is shown once, at creation. Tokens are short-lived — fetch one per session or when the previous one expires, not per request. What the token is allowed to do comes from the scopes granted to the client, not from anything in this request.

        This endpoint lives on the authorization server, so its errors follow OAuth 2.0 (RFC 6749) rather than the problem documents the rest of this API returns.
      operationId: createAccessToken
      requestBody:
        content:
          application/x-www-form-urlencoded:
            examples:
              clientCredentials:
                value:
                  client_id: com.accountflow.api.prod.4be9a1c803f2
                  client_secret: your-client-secret
                  grant_type: client_credentials
            schema:
              type: object
              properties:
                client_id:
                  type: string
                  description: The API client's id.
                client_secret:
                  type: string
                  description: The secret shown once when the client was created.
                grant_type:
                  type: string
                  description: Always `client_credentials`.
                  enum:
                  - client_credentials
              required:
              - client_id
              - client_secret
              - grant_type
        required: true
      responses:
        "200":
          content:
            application/json:
              examples:
                token:
                  value:
                    access_token: eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9…
                    expires_in: 300
                    scope: ledger:read companies:read
                    token_type: Bearer
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                    description: The bearer token. Send it in the Authorization header.
                  expires_in:
                    type: integer
                    description: Lifetime in seconds.
                  scope:
                    type: string
                    description: Scopes carried by the token.
                  token_type:
                    type: string
                    description: Always `Bearer`.
          description: A bearer token.
        "401":
          content:
            application/json:
              examples:
                invalidClient:
                  value:
                    error: invalid_client
                    error_description: Invalid client or Invalid client credentials
              schema:
                type: object
                description: OAuth 2.0 error (RFC 6749) — not this API's problem-document
                  shape.
                properties:
                  error:
                    type: string
                    description: "Machine-readable code, e.g. `invalid_client`."
                  error_description:
                    type: string
          description: "The client id or secret is wrong, or the client is disabled."
      security: []
      summary: Get an access token
      tags:
      - Authentication
    servers:
    - description: Authorization server
      url: https://auth.lab.accountflow.com/realms/accountflow
  /v1/companies:
    get:
      description: Cursor-paginated list of the companies you can read. Iterate with
        next_cursor; cursors are bound to your credentials and this endpoint's filters.
      operationId: listCompanies
      parameters:
      - description: Opaque cursor from a previous page's pagination.next_cursor.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Rows per page (1–200, default 50)."
        in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageCompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:read
      summary: List companies
      tags:
      - Companies
  /v1/companies/{companyId}:
    delete:
      description: "Soft delete: the company disappears from the API (404) and can\
        \ be restored with POST /restore. Idempotent."
      operationId: deleteCompany
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeleteCompanyRequest"
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletionResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:write
      summary: Delete a company
      tags:
      - Companies
    get:
      operationId: getCompany
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:read
      summary: Get a company
      tags:
      - Companies
    patch:
      description: "Patch semantics: absent fields stay unchanged."
      operationId: updateCompany
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateCompanyRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:write
      summary: Update a company
      tags:
      - Companies
  /v1/companies/{companyId}/accounts:
    get:
      description: "The company's accounts for one accounting year. Omit `year` for\
        \ the current accounting year. Accounts are identified by their account number,\
        \ which is stable across years."
      operationId: listAccounts
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - description: Accounting year; omitted = the current accounting year.
        in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageLedgerAccountResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - ledger:read
      summary: List the chart of accounts
      tags:
      - General Ledger
  /v1/companies/{companyId}/accounts/{accountNumber}:
    delete:
      description: "Delete one account from the chart of one accounting year (the\
        \ current one when year is omitted). Only an unused account can go (409 account_in_use\
        \ otherwise); to retire an account that has history, import it with hidden:\
        \ true. All or nothing: if anything requested is in use, the answer is 409\
        \ with reason and an inUse list of ids and what depends on each, and nothing\
        \ is deleted. Returns 202 with the import to poll; one import or correction\
        \ per kind and company runs at a time."
      operationId: deleteAccount
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: accountNumber
        required: true
        schema:
          type: string
      - in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Delete an unused account
      tags:
      - Imports
    get:
      description: "One account of the chart, addressed by its account number. Omit\
        \ `year` for the current accounting year."
      operationId: getAccount
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - description: The account number.
        example: 3000
        in: path
        name: accountNumber
        required: true
        schema:
          type: string
      - description: Accounting year; omitted = the current accounting year.
        in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LedgerAccountResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - ledger:read
      summary: Get one account
      tags:
      - General Ledger
  /v1/companies/{companyId}/actions/disable:
    post:
      description: "Pauses the client: it stays readable with status 'disabled'. Idempotent."
      operationId: disableCompany
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:write
      summary: Disable a company
      tags:
      - Companies
  /v1/companies/{companyId}/actions/enable:
    post:
      description: Idempotent.
      operationId: enableCompany
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:write
      summary: Enable a company
      tags:
      - Companies
  /v1/companies/{companyId}/bank/accounts:
    get:
      operationId: listBankAccounts
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageBankAccount"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - bank:read
      summary: List the company's bank accounts
      tags:
      - Bank & Reconciliation
  /v1/companies/{companyId}/bank/accounts/{bankAccountId}/reconciliation-summary:
    get:
      description: "Twelve periods with group/entry counts, staleness, and the firm's\
        \ period-approval status on the mapped GL account."
      operationId: getReconciliationSummary
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: bankAccountId
        required: true
        schema:
          type: string
          format: uuid
      - in: query
        name: year
        required: true
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReconciliationSummary"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - reconciliation:read
      summary: Per-period reconciliation summary
      tags:
      - Bank & Reconciliation
  /v1/companies/{companyId}/bank/accounts/{bankAccountId}/reconciliations:
    get:
      operationId: listReconciliations
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: bankAccountId
        required: true
        schema:
          type: string
          format: uuid
      - in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      - in: query
        name: period
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageReconciliation"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - reconciliation:read
      summary: List reconciliation groups for a bank account
      tags:
      - Bank & Reconciliation
  /v1/companies/{companyId}/bank/accounts/{bankAccountId}/transactions:
    get:
      description: "Cursor-paginated, newest first. reconciliationStatus is computed\
        \ on every read: unreconciled | reconciled | stale."
      operationId: listBankTransactions
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: bankAccountId
        required: true
        schema:
          type: string
          format: uuid
      - in: query
        name: from
        required: false
        schema:
          type: string
          format: date
      - in: query
        name: to
        required: false
        schema:
          type: string
          format: date
      - description: unreconciled | reconciled | stale.
        in: query
        name: reconciliation_status
        required: false
        schema:
          type: string
      - in: query
        name: cursor
        required: false
        schema:
          type: string
      - in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageBankTransaction"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - bank:read
      summary: List bank transactions
      tags:
      - Bank & Reconciliation
  /v1/companies/{companyId}/bank/reconciliations:
    post:
      description: Creates one reconciliation group for a period. A GL line already
        reconciled that year is a 409. Correction = delete and recreate — groups are
        not editable.
      operationId: createReconciliation
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateReconciliationRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Reconciliation"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - reconciliation:write
      summary: Reconcile bank transactions against GL lines
      tags:
      - Bank & Reconciliation
  /v1/companies/{companyId}/dimensions:
    get:
      description: "The company's dimension values (departments, projects, cost centres,\
        \ ...) by their stable, company-wide keys — the keys general-ledger lines\
        \ refer to."
      operationId: listDimensions
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: query
        name: cursor
        required: false
        schema:
          type: string
      - in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageMasterDataResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - ledger:read
      summary: List dimension values
      tags:
      - General Ledger
  /v1/companies/{companyId}/dimensions/{key}:
    delete:
      description: "Delete one dimension value nothing has ever referenced (409 dimension_in_use\
        \ otherwise). All or nothing: if anything requested is in use, the answer\
        \ is 409 with reason and an inUse list of ids and what depends on each, and\
        \ nothing is deleted. Returns 202 with the import to poll; one import or correction\
        \ per kind and company runs at a time."
      operationId: deleteDimension
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: key
        required: true
        schema:
          type: string
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Delete an unused dimension value
      tags:
      - Imports
  /v1/companies/{companyId}/documents:
    get:
      operationId: listDocuments
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - description: Opaque cursor from a previous page.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Rows per page (1–200, default 50)."
        in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageDocumentResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:read
      summary: List a company's documents
      tags:
      - Documents
    post:
      description: "Step 1 of 2: declare the document (JSON), receive a signed PUT\
        \ URL, upload the binary directly to storage, then POST /complete. The document\
        \ does not exist until completion."
      operationId: createDocumentUpload
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateUploadRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentUploadResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:write
      summary: Start an upload
      tags:
      - Documents
  /v1/companies/{companyId}/general-ledger/lines:
    get:
      description: "Cursor-paginated GL lines for one accounting year, ordered by\
        \ period then line id. Zero-amount lines are included. Line ids are stable\
        \ across re-imports."
      operationId: listGeneralLedgerLines
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - description: Accounting year; omitted = the current accounting year.
        in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      - description: Filter to one account number.
        example: 3000
        in: query
        name: account
        required: false
        schema:
          type: string
      - description: Filter to one fiscal period (1–12).
        in: query
        name: period
        required: false
        schema:
          type: integer
          format: int32
      - description: Opaque cursor from a previous page.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Rows per page (1–200, default 50)."
        in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageGlLineResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - ledger:read
      summary: List general-ledger lines
      tags:
      - General Ledger
  /v1/companies/{companyId}/imports:
    get:
      description: "The company's imports and corrections, newest first."
      operationId: listImports
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: query
        name: cursor
        required: false
        schema:
          type: string
      - in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: List imports
      tags:
      - Imports
  /v1/companies/{companyId}/imports/accounts:
    post:
      description: "Push up to 10 000 accounts for one accounting year. Existing account\
        \ codes are updated in place; their standard-account mapping is preserved.\
        \ The company must be bound to the Api accounting system (409 company_not_api_managed\
        \ otherwise), and one accounts import per company runs at a time (409 job_in_flight).\
        \ Returns 202 with the import; poll it, or the job it names, until succeeded\
        \ or failed."
      operationId: importAccounts
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AccountsImportRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Import the chart of accounts
      tags:
      - Imports
  /v1/companies/{companyId}/imports/dimensions:
    post:
      description: "Push up to 10 000 dimension values (departments, projects, cost\
        \ centres, ...). Keys are company-wide and stable; an existing key is updated\
        \ in place. Returns 202 with the import."
      operationId: importDimensions
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DimensionsImportRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Import dimension values
      tags:
      - Imports
  /v1/companies/{companyId}/imports/general-ledger-lines:
    post:
      description: "Push up to 10 000 general-ledger lines for one accounting year.\
        \ Lines are merged by id: a known id is updated in place, a new one inserted;\
        \ nothing is removed. Every accountCode must already be in the chart for that\
        \ year (422 unknown_account_codes otherwise); unknown dimension and sub-ledger\
        \ keys are created. Periods are 1–12. Returns 202 with the import."
      operationId: importGeneralLedgerLines
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GlLinesImportRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Import general-ledger lines
      tags:
      - Imports
  /v1/companies/{companyId}/imports/general-ledger-lines/deletions:
    post:
      description: "Delete up to 10 000 lines of one accounting year by the ids they\
        \ were pushed with. A line is in use once it is matched, reconciled, commented,\
        \ flagged, accrued, or tied to an asset or payroll (409 lines_in_use). Deleted\
        \ lines keep their full history; ids the ledger does not have are reported\
        \ on the import, not errors. To change a line's values, re-send it with the\
        \ same id instead. All or nothing: if anything requested is in use, the answer\
        \ is 409 with reason and an inUse list of ids and what depends on each, and\
        \ nothing is deleted. Returns 202 with the import to poll; one import or correction\
        \ per kind and company runs at a time."
      operationId: deleteGeneralLedgerLines
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeletionRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Delete general-ledger lines
      tags:
      - Imports
  /v1/companies/{companyId}/imports/open-items:
    post:
      description: "Push up to 10 000 customer or supplier open items with their matches.\
        \ incremental updates what is sent and sourceDeleted retires an item; full,\
        \ full_refresh and baseline snapshots retire items and matches absent from\
        \ the snapshot. The whole import fails on any invalid item. Returns 202 with\
        \ the import."
      operationId: importOpenItems
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/OpenItemsImportRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Import sub-ledger open items
      tags:
      - Imports
  /v1/companies/{companyId}/imports/opening-balances:
    post:
      description: Push up to 10 000 opening-balance rows for one accounting year.
        Every accountCode must already be in the chart for that year (422 unknown_account_codes
        otherwise); re-sending an id updates the row. Returns 202 with the import.
      operationId: importOpeningBalances
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/OpeningBalancesImportRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Import opening balances
      tags:
      - Imports
  /v1/companies/{companyId}/imports/opening-balances/deletions:
    post:
      description: "Delete opening-balance rows of one accounting year by the ids\
        \ they were pushed with. A row is in use once it has been split, itemised,\
        \ matched or commented (409 opening_balances_in_use). The trial balance's\
        \ opening column is recomputed. All or nothing: if anything requested is in\
        \ use, the answer is 409 with reason and an inUse list of ids and what depends\
        \ on each, and nothing is deleted. Returns 202 with the import to poll; one\
        \ import or correction per kind and company runs at a time."
      operationId: deleteOpeningBalances
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeletionRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Delete opening-balance rows
      tags:
      - Imports
  /v1/companies/{companyId}/imports/readiness:
    get:
      description: "Preflight before importing: whether the company is bound to the\
        \ Api accounting system, what each API-managed year already holds, and the\
        \ next step. An unbound company is reported in blockers, not refused."
      operationId: getImportReadiness
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportReadinessResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Check import readiness
      tags:
      - Imports
  /v1/companies/{companyId}/imports/sub-ledgers:
    post:
      description: "Push up to 10 000 sub-ledgers (customers, suppliers, ...). Keys\
        \ are company-wide and stable; an existing key is updated in place. Returns\
        \ 202 with the import."
      operationId: importSubLedgers
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubLedgersImportRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Import sub-ledgers
      tags:
      - Imports
  /v1/companies/{companyId}/imports/{importId}:
    get:
      description: "Status, row counters, line errors and the job and dataset ids\
        \ of one import."
      operationId: getImport
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: importId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Get an import
      tags:
      - Imports
  /v1/companies/{companyId}/reconciliations/{reconciliationId}:
    delete:
      description: Dissolves the group; its transactions and GL lines become unreconciled
        again.
      operationId: deleteReconciliation
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: reconciliationId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReconciliationDeletionResult"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - reconciliation:write
      summary: Unmatch a reconciliation group
      tags:
      - Bank & Reconciliation
    get:
      operationId: getReconciliation
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: reconciliationId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Reconciliation"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - reconciliation:read
      summary: Get one reconciliation group with its entries
      tags:
      - Bank & Reconciliation
  /v1/companies/{companyId}/restore:
    post:
      description: Brings a soft-deleted company back in its prior state (active or
        disabled). Refused (409) when the deletion was part of an organization cascade.
      operationId: restoreCompany
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:write
      summary: Restore a deleted company
      tags:
      - Companies
  /v1/companies/{companyId}/sub-ledgers:
    get:
      description: "The company's sub-ledgers (customers, suppliers, ...) by their\
        \ stable, company-wide keys — the keys general-ledger lines and open items\
        \ refer to."
      operationId: listSubLedgers
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: query
        name: cursor
        required: false
        schema:
          type: string
      - in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageMasterDataResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - ledger:read
      summary: List sub-ledgers
      tags:
      - General Ledger
  /v1/companies/{companyId}/sub-ledgers/{key}:
    delete:
      description: "Delete one sub-ledger nothing has ever referenced (409 sub_ledger_in_use\
        \ otherwise). All or nothing: if anything requested is in use, the answer\
        \ is 409 with reason and an inUse list of ids and what depends on each, and\
        \ nothing is deleted. Returns 202 with the import to poll; one import or correction\
        \ per kind and company runs at a time."
      operationId: deleteSubLedger
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: key
        required: true
        schema:
          type: string
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - imports:write
      summary: Delete an unused sub-ledger
      tags:
      - Imports
  /v1/companies/{companyId}/trial-balance:
    get:
      description: "Opening balance, labeled monthly movements, and closing balance\
        \ per account for one accounting year. The closing balance at period N is\
        \ openingBalance plus the movements of periods 1..N."
      operationId: getTrialBalance
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - description: Accounting year; omitted = the current accounting year.
        in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TrialBalanceResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - ledger:read
      summary: Get the trial balance
      tags:
      - General Ledger
  /v1/companies/{companyId}/vat/terms:
    get:
      description: The company's VAT filing terms with their reconciliation status
        and totals (decimal NOK).
      operationId: listVatTerms
      parameters:
      - in: path
        name: companyId
        required: true
        schema:
          type: string
          format: uuid
      - description: Filter to one filing year.
        in: query
        name: year
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageVatTermResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - vat:read
      summary: List VAT filing terms
      tags:
      - VAT
  /v1/documents/{documentId}:
    delete:
      description: "Soft delete: the document 404s until restored; the binary stays\
        \ in storage. Idempotent."
      operationId: deleteDocument
      parameters:
      - in: path
        name: documentId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentDeletionResult"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:write
      summary: Delete a document
      tags:
      - Documents
    get:
      operationId: getDocument
      parameters:
      - in: path
        name: documentId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:read
      summary: Get a document's metadata
      tags:
      - Documents
    patch:
      operationId: renameDocument
      parameters:
      - in: path
        name: documentId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RenameRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:write
      summary: Rename a document
      tags:
      - Documents
  /v1/documents/{documentId}/complete:
    post:
      description: "Step 2 of 2: after the binary is uploaded, verifies the object\
        \ (size and content type must match the declaration) and creates the document.\
        \ Emits document.uploaded."
      operationId: completeDocumentUpload
      parameters:
      - in: path
        name: documentId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:write
      summary: Complete an upload
      tags:
      - Documents
  /v1/documents/{documentId}/download-url:
    get:
      description: Returns a short-lived signed GET URL for the binary. Every issue
        is recorded in the document's access log.
      operationId: getDocumentDownloadUrl
      parameters:
      - in: path
        name: documentId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DownloadUrlResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:read
      summary: Get a download URL
      tags:
      - Documents
  /v1/documents/{documentId}/restore:
    post:
      description: Idempotent.
      operationId: restoreDocument
      parameters:
      - in: path
        name: documentId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DocumentResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - documents:write
      summary: Restore a deleted document
      tags:
      - Documents
  /v1/jobs/{jobId}:
    get:
      description: "Visible only to the API client that submitted it. Poll until status\
        \ is succeeded, failed, or expired; job completion also produces a job.succeeded/job.failed\
        \ webhook event."
      operationId: getJob
      parameters:
      - in: path
        name: jobId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JobResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2: []
      summary: Get a job's status
      tags:
      - Jobs
  /v1/organizations/{organizationId}/access-policies:
    get:
      operationId: listAccessPolicies
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageAccessPolicyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: List access policies
      tags:
      - Access Management
    post:
      description: "The policy is one document: name, default flag, and its rules.\
        \ Marking it default demotes the previous default."
      operationId: createAccessPolicy
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePolicyRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccessPolicyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: Create an access policy
      tags:
      - Access Management
  /v1/organizations/{organizationId}/access-policies/{policyId}:
    get:
      operationId: getAccessPolicy
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: policyId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccessPolicyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: Get one access policy
      tags:
      - Access Management
    patch:
      description: "Patch semantics for the scalar fields; a rules array, when present,\
        \ replaces the whole rule set."
      operationId: updateAccessPolicy
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: policyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePolicyRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccessPolicyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: Update an access policy
      tags:
      - Access Management
  /v1/organizations/{organizationId}/access-policies/{policyId}/actions/archive:
    post:
      description: Archived policies grant nothing and stay for audit; they are never
        hard-deleted. Idempotent.
      operationId: archiveAccessPolicy
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: policyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccessPolicyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: Archive an access policy
      tags:
      - Access Management
  /v1/organizations/{organizationId}/access-policies/{policyId}/assignments:
    post:
      description: The user's effective access becomes the union of all assigned policies
        plus the organization's default policy.
      operationId: assignAccess
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: policyId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AssignRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssignmentResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: Assign a user to a policy
      tags:
      - Access Management
  /v1/organizations/{organizationId}/access-policies/{policyId}/assignments/{userId}:
    delete:
      operationId: revokeAccess
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: policyId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: userId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccessRevocationResult"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - access:manage
      summary: Revoke a user's assignment
      tags:
      - Access Management
  /v1/organizations/{organizationId}/companies:
    post:
      description: "Registers a new accounting client under one of your organizations,\
        \ provisions its settings and first ledger, and grants access per the organization's\
        \ policies."
      operationId: createCompany
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateCompanyRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - companies:write
      summary: Create a company
      tags:
      - Companies
  /v1/organizations/{organizationId}/users:
    get:
      description: Members of the organization. Disabled users are listed with status
        'disabled'; deleted users are not represented.
      operationId: listOrgUsers
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageUserResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - users:read
      summary: List the organization's users
      tags:
      - Users
  /v1/organizations/{organizationId}/users/{userId}:
    get:
      operationId: getUser
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: userId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - users:read
      summary: Get one user
      tags:
      - Users
  /v1/organizations/{organizationId}/webhooks:
    get:
      operationId: listWebhookEndpoints
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageWebhookEndpointResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: List webhook endpoints
      tags:
      - Webhooks
    post:
      description: The response carries the signing secret EXACTLY ONCE. The endpoint
        starts in pending_verification and must echo the verification challenge (a
        webhook.verification POST) with a 2xx before events flow.
      operationId: createWebhookEndpoint
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWebhookRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointCreatedResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: Register a webhook endpoint
      tags:
      - Webhooks
  /v1/organizations/{organizationId}/webhooks/{webhookId}:
    delete:
      operationId: deleteWebhookEndpoint
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: webhookId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointDeletionResult"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: Delete a webhook endpoint
      tags:
      - Webhooks
    get:
      operationId: getWebhookEndpoint
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: webhookId
        required: true
        schema:
          type: string
          format: uuid
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: Get one webhook endpoint
      tags:
      - Webhooks
    patch:
      description: Patch semantics. Changing the URL puts the endpoint back into pending_verification
        until the new URL answers the challenge.
      operationId: updateWebhookEndpoint
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: webhookId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateWebhookRequest"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: Update a webhook endpoint
      tags:
      - Webhooks
  /v1/organizations/{organizationId}/webhooks/{webhookId}/actions/rotate-secret:
    post:
      description: Returns the NEW secret exactly once; old signatures stop validating
        immediately.
      operationId: rotateWebhookSecret
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: webhookId
        required: true
        schema:
          type: string
          format: uuid
      - in: header
        name: Idempotency-Key
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEndpointCreatedResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: Rotate the signing secret
      tags:
      - Webhooks
  /v1/organizations/{organizationId}/webhooks/{webhookId}/deliveries:
    get:
      description: "The self-debugging surface: every attempt with status code, error,\
        \ and payload, newest first, cursor-paginated."
      operationId: listWebhookDeliveries
      parameters:
      - in: path
        name: organizationId
        required: true
        schema:
          type: string
          format: uuid
      - in: path
        name: webhookId
        required: true
        schema:
          type: string
          format: uuid
      - description: Opaque cursor from a previous page.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Rows per page (1–200, default 50)."
        in: query
        name: page_size
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageWebhookDeliveryResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      security:
      - oauth2:
        - webhooks:manage
      summary: List delivery attempts
      tags:
      - Webhooks
  /v1/whoami:
    get:
      description: "Returns the authenticated API client's identity, mode, and organization\
        \ scope. Use it to verify credentials before calling anything else."
      operationId: getCallerIdentity
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WhoamiResponse"
          description: OK
        "400":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: displayName must not be blank
                    error: validation_failed
                    requestId: d4f0a1b2-…
                    status: 400
                    title: Validation Failed
                    type: https://api.accountflow.com/errors/validation-failed
              schema:
                $ref: "#/components/schemas/Problem"
          description: Malformed request — a required field is missing or a value
            is out of range. The `detail` names the field.
        "500":
          content:
            application/problem+json:
              examples:
                problem:
                  value:
                    detail: Unexpected error
                    error: internal_error
                    requestId: d4f0a1b2-…
                    status: 500
                    title: Internal Server Error
                    type: https://api.accountflow.com/errors/internal-error
              schema:
                $ref: "#/components/schemas/Problem"
          description: "Unexpected server error. Nothing about the request was wrong\
            \ — retry is safe, and mutations retried with the same Idempotency-Key\
            \ are deduplicated."
      summary: Who am I
      tags:
      - Identity
components:
  schemas:
    AccessPolicyResponse:
      type: object
      description: "An access policy: a named set of company access rules, assignable\
        \ to users."
      properties:
        createdAt:
          type: string
          format: date-time
        description:
          type: string
          nullable: true
        id:
          type: string
          format: uuid
          description: The policy's stable identifier.
        isDefault:
          type: boolean
          description: "The org's baseline policy, applied to every member on top\
            \ of explicit grants."
        name:
          type: string
          example: Standard bookkeeper
        rules:
          type: array
          items:
            $ref: "#/components/schemas/Rule"
        status:
          type: string
          description: '''ACTIVE'' or ''ARCHIVED''. Archived policies grant nothing
            and are kept for audit.'
    AccessRevocationResult:
      type: object
      description: Confirmation of a revocation.
      properties:
        policyId:
          type: string
          format: uuid
        status:
          type: string
          example: revoked
        userId:
          type: string
          format: uuid
    AccountLine:
      type: object
      description: One account of the chart.
      properties:
        accountCategory:
          type: string
          example: Balance
          nullable: true
        accountCode:
          type: string
          description: The account number as the ledger knows it.
          example: "1920"
        accountDescription:
          type: string
          example: Bankinnskudd
          nullable: true
        currencyCode:
          type: string
          example: NOK
          nullable: true
        hidden:
          type: boolean
          description: Hide the account in the application. Omit to leave an existing
            account's flag unchanged.
          nullable: true
    AccountsImportRequest:
      type: object
      properties:
        accounts:
          type: array
          items:
            $ref: "#/components/schemas/AccountLine"
        year:
          type: integer
          format: int32
    AssignRequest:
      type: object
      properties:
        userId:
          type: string
          format: uuid
    AssignmentResponse:
      type: object
      description: A user's assignment to an access policy.
      properties:
        id:
          type: string
          format: uuid
          description: The assignment's stable identifier.
        policyId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
    Association:
      type: object
      description: "An attachment target: the whole company, or one voucher (transaction)."
      nullable: true
      properties:
        type:
          type: string
          example: transaction
        value:
          type: string
          description: "The company id, or the voucher's transaction key."
    AssociationInput:
      type: object
      properties:
        type:
          type: string
          example: transaction
        value:
          type: string
          description: Required for 'transaction'; ignored for 'company'.
          nullable: true
    BankAccount:
      type: object
      description: A bank account connected to the company.
      properties:
        accountNumber:
          type: string
          nullable: true
        accountType:
          type: string
          nullable: true
        availableBalance:
          type: number
          nullable: true
        balanceUpdatedAt:
          type: string
          format: date-time
          description: When the balances were last synced from the bank.
          nullable: true
        bic:
          type: string
          nullable: true
        bookedBalance:
          type: number
          nullable: true
        currencyCode:
          type: string
          example: NOK
          nullable: true
        glAccountNumber:
          type: string
          description: "The mapped GL account number, when reconciliation is set up."
          nullable: true
        iban:
          type: string
          nullable: true
        id:
          type: string
          format: uuid
          description: The account's stable identifier.
        name:
          type: string
          nullable: true
        status:
          type: string
          description: active | closed | inactive.
          example: active
    BankEntry:
      type: object
      description: One matched bank transaction.
      properties:
        amount:
          type: number
        transactionId:
          type: string
          format: uuid
    BankTransaction:
      type: object
      description: A bank transaction with its computed reconciliation state.
      properties:
        amount:
          type: number
          description: Signed amount; debits are negative.
        bookingDate:
          type: string
          format: date
          nullable: true
        counterpartyAccount:
          type: string
          nullable: true
        counterpartyName:
          type: string
          nullable: true
        currencyCode:
          type: string
          example: NOK
          nullable: true
        description:
          type: string
          nullable: true
        id:
          type: string
          format: uuid
          description: The transaction's stable identifier.
        reconciliationId:
          type: string
          format: uuid
          description: "The reconciliation group, when matched."
          nullable: true
        reconciliationStatus:
          type: string
          description: "Computed on every read: unreconciled | reconciled | stale.\
            \ Stale means the matched data changed after matching — re-reconcile."
          example: reconciled
        remittanceInfo:
          type: string
          nullable: true
        source:
          type: string
          description: provider_api | file_upload.
        status:
          type: string
          description: booked | pending.
          example: booked
        valueDate:
          type: string
          format: date
          nullable: true
    CompanyResponse:
      type: object
      description: An accounting client (company) within your reach.
      properties:
        companyType:
          type: string
          description: Legal form.
          example: AS
          nullable: true
        countryCode:
          type: string
          description: ISO country code.
          example: "NO"
          nullable: true
        createdAt:
          type: string
          format: date-time
          description: When the company was registered in Accountflow.
        currentAccountingYear:
          type: integer
          format: int32
          description: The accounting year currently being worked.
          nullable: true
        fiscalYearEnd:
          type: string
          format: date
          description: End of the current fiscal year.
        fiscalYearStart:
          type: string
          format: date
          description: Start of the current fiscal year.
        id:
          type: string
          format: uuid
          description: The company's stable identifier.
        name:
          type: string
          description: Display name.
          example: Fjellheim Regnskap AS
        organizationId:
          type: string
          format: uuid
          description: The organization (accounting firm) this company belongs to.
        organizationNumber:
          type: string
          description: Norwegian organization number.
          example: "987654325"
          nullable: true
        periodType:
          type: string
          description: Accounting period granularity.
          example: MONTHLY
          nullable: true
        status:
          type: string
          description: "Lifecycle state: 'active' or 'disabled'. Deleted companies\
            \ are not represented — they 404 until restored."
          example: active
    CreateCompanyRequest:
      type: object
      properties:
        assetsEnabled:
          type: boolean
          nullable: true
        companyNumber:
          type: string
        companyType:
          type: string
          nullable: true
        countryCode:
          type: string
          nullable: true
        fiscalYearEnd:
          type: string
          format: date
          nullable: true
        fiscalYearStart:
          type: string
          format: date
          nullable: true
        mainAccountantUserId:
          type: string
          format: uuid
          nullable: true
        name:
          type: string
        obMonth:
          type: integer
          format: int32
          nullable: true
        ownerUserId:
          type: string
          format: uuid
        payrollEnabled:
          type: boolean
          nullable: true
        periodType:
          type: string
          nullable: true
        vatEnabled:
          type: boolean
          nullable: true
    CreatePolicyRequest:
      type: object
      properties:
        description:
          type: string
          nullable: true
        isDefault:
          type: boolean
          nullable: true
        name:
          type: string
        rules:
          type: array
          items:
            $ref: "#/components/schemas/RuleInput"
          nullable: true
    CreateReconciliationRequest:
      type: object
      properties:
        bankAccountId:
          type: string
          format: uuid
        lineIds:
          type: array
          items:
            type: string
          nullable: true
        note:
          type: string
          nullable: true
        period:
          type: integer
          format: int32
        periodYear:
          type: integer
          format: int32
        transactionIds:
          type: array
          items:
            type: string
            format: uuid
          nullable: true
    CreateUploadRequest:
      type: object
      properties:
        association:
          $ref: "#/components/schemas/AssociationInput"
        displayName:
          type: string
        mimeType:
          type: string
        sizeBytes:
          type: integer
          format: int64
    CreateWebhookRequest:
      type: object
      properties:
        description:
          type: string
          nullable: true
        eventTypes:
          type: array
          items:
            type: string
          nullable: true
        url:
          type: string
    DeleteCompanyRequest:
      type: object
      properties:
        reason:
          type: string
          nullable: true
    DeletionRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
        year:
          type: integer
          format: int32
    DeletionResponse:
      type: object
      description: Confirmation of a (soft) deletion; restore is available via POST
        /restore.
      properties:
        deletedAt:
          type: string
          format: date-time
        id:
          type: string
          format: uuid
        status:
          type: string
          example: deleted
    DimensionsImportRequest:
      type: object
      properties:
        dimensions:
          type: array
          items:
            $ref: "#/components/schemas/MasterLine"
    DocumentDeletionResult:
      type: object
      description: Confirmation of a (soft) deletion; restore via POST /restore.
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          example: deleted
    DocumentResponse:
      type: object
      description: "A document. Download the binary via GET /v1/documents/{id}/download-url."
      properties:
        association:
          $ref: "#/components/schemas/Association"
        companyId:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        createdBy:
          type: string
          format: uuid
          description: The identity that uploaded it (a user or a service account).
        displayName:
          type: string
          example: Faktura 2026-042.pdf
        id:
          type: string
          format: uuid
          description: The document's stable identifier.
        mimeType:
          type: string
          example: application/pdf
          nullable: true
        organizationId:
          type: string
          format: uuid
        sizeBytes:
          type: integer
          format: int64
          nullable: true
        updatedAt:
          type: string
          format: date-time
    DocumentUploadResponse:
      type: object
      description: "An upload slot: PUT the binary to the signed URL, then POST /complete."
      properties:
        displayName:
          type: string
        documentId:
          type: string
          format: uuid
          description: The id the document will have once completed.
        mimeType:
          type: string
        sizeBytes:
          type: integer
          format: int64
        upload:
          $ref: "#/components/schemas/Upload"
    DownloadUrlResponse:
      type: object
      description: A short-lived signed URL for the binary. Fetch promptly; request
        a fresh one when it expires.
      properties:
        expiresAt:
          type: string
          format: date-time
        filename:
          type: string
          example: Faktura 2026-042.pdf
        url:
          type: string
    GlEntry:
      type: object
      description: One matched GL line (by its stable line id).
      properties:
        amount:
          type: number
        lineId:
          type: string
          description: The GL line's stable identity.
    GlLine:
      type: object
      description: One general-ledger line.
      properties:
        accountCode:
          type: string
          example: "3000"
        amount:
          type: number
          description: "Signed amount in the company's base currency, as a decimal\
            \ string."
          example: -1250.0
        description:
          type: string
          nullable: true
        dimensionKeys:
          type: array
          items:
            type: string
            nullable: true
          nullable: true
        exchangeRate:
          type: number
          nullable: true
        id:
          type: string
          description: Your stable id for this line; re-sending the same id updates
            it in place.
          example: INV-2025-000123-1
        lineDescription:
          type: string
          nullable: true
        period:
          type: integer
          format: int32
          description: Fiscal period 1–12.
          example: 3
        postedDate:
          type: string
          format: date
          nullable: true
        subLedgerKeys:
          type: array
          items:
            type: string
            nullable: true
          nullable: true
        taxAmount:
          type: number
          nullable: true
        taxBase:
          type: number
          nullable: true
        taxCode:
          type: string
          description: The ERP's VAT code for the line.
          nullable: true
        taxPercentage:
          type: number
          nullable: true
        transactionAmount:
          type: number
          nullable: true
        transactionCurrencyCode:
          type: string
          example: NOK
          nullable: true
        transactionDate:
          type: string
          format: date
          nullable: true
        transactionId:
          type: string
          description: The transaction (voucher) id this line belongs to.
          example: V-2025-0456
        transactionNo:
          type: string
          description: The voucher number as shown to accountants.
          example: "456"
    GlLineResponse:
      type: object
      description: A general-ledger line.
      properties:
        accountNumber:
          type: string
          description: The account number this line is posted to.
          example: "3000"
        amount:
          type: number
          description: Amount in the company's base currency (signed; debit positive).
        baseCurrency:
          type: string
          description: The base/reporting currency.
          example: NOK
          nullable: true
        description:
          type: string
          description: Line description.
          nullable: true
        exchangeRate:
          type: number
          description: base = transactionAmount × exchangeRate.
          nullable: true
        lineId:
          type: string
          description: Stable line identifier (survives re-imports).
        period:
          type: integer
          format: int32
          description: Fiscal period 1–12.
        postedDate:
          type: string
          format: date
          description: Posting date (bokføringsdato).
          nullable: true
        sourceLineId:
          type: string
          description: "The id the line was pushed with through the API imports, when\
            \ it was; absent for lines fetched from an ERP."
          nullable: true
        taxAmount:
          type: number
          description: "VAT amount on the line, base currency."
          nullable: true
        taxCode:
          type: string
          description: The ERP's VAT code for the line.
          nullable: true
        transactionAmount:
          type: number
          description: Amount in the original document currency.
          nullable: true
        transactionCurrency:
          type: string
          description: The document currency.
          example: EUR
          nullable: true
        transactionDate:
          type: string
          format: date
          description: Document/transaction date (bilagsdato).
          nullable: true
        voucherNo:
          type: string
          description: The voucher (bilag) number this line belongs to.
          nullable: true
        year:
          type: integer
          format: int32
          description: Accounting year.
    GlLinesImportRequest:
      type: object
      properties:
        lines:
          type: array
          items:
            $ref: "#/components/schemas/GlLine"
        mode:
          type: string
          description: merge (default). replace is not available yet.
          nullable: true
        year:
          type: integer
          format: int32
    ImportReadinessResponse:
      type: object
      description: "What an API-managed company already holds, and what to import\
        \ next."
      properties:
        accountingSystem:
          type: string
          description: "The accounting system the current ledger is bound to, if any."
          nullable: true
        apiManaged:
          type: boolean
          description: Whether the company's current ledger is bound to the Api accounting
            system. Imports are refused (409 company_not_api_managed) while this is
            false.
        blockers:
          type: array
          description: "What prevents importing right now: company_not_api_managed,\
            \ no_current_ledger, no_accounts (the current year has no chart yet)."
          items:
            type: string
            description: "What prevents importing right now: company_not_api_managed,\
              \ no_current_ledger, no_accounts (the current year has no chart yet)."
        companyId:
          type: string
          format: uuid
        currentYear:
          type: integer
          format: int32
          description: The current accounting year.
          nullable: true
        dimensions:
          type: integer
          format: int64
          description: Dimension values the company holds (company-wide).
        nextStep:
          type: string
          description: bind_api_accounting_system | import_accounts | import_opening_balances
            | import_general_ledger_lines | ready
          example: import_accounts
        subLedgers:
          type: integer
          format: int64
          description: Sub-ledgers the company holds (company-wide).
        warnings:
          type: array
          description: "What does not block but deserves attention: unmapped_accounts\
            \ (accounts without a standard-account mapping do not take part in reconciliation\
            \ rules)."
          items:
            type: string
            description: "What does not block but deserves attention: unmapped_accounts\
              \ (accounts without a standard-account mapping do not take part in reconciliation\
              \ rules)."
        years:
          type: array
          description: "One entry per accounting year that has an API-managed ledger,\
            \ oldest first."
          items:
            $ref: "#/components/schemas/Year"
    ImportResponse:
      type: object
      description: An import or correction request. Poll until status is succeeded
        or failed.
      properties:
        companyId:
          type: string
          format: uuid
          description: The company the data was imported into.
        createdAt:
          type: string
          format: date-time
        datasetId:
          type: string
          format: uuid
          description: The dataset id recorded on every row this import touched (provenance).
        failureReason:
          type: string
          description: "Why the import failed, present when status is failed."
          nullable: true
        finishedAt:
          type: string
          format: date-time
          nullable: true
        id:
          type: string
          format: uuid
          description: The import's stable identifier.
        jobId:
          type: string
          format: uuid
          description: "The job running this import; GET /v1/jobs/{jobId} shows the\
            \ same lifecycle."
        kind:
          type: string
          description: accounts | dimensions | sub_ledgers | opening_balances | general_ledger_lines
            | ...
        lineCount:
          type: integer
          format: int32
          description: Lines accepted in the request.
        mode:
          type: string
          description: merge | replace for general-ledger lines; the snapshot mode
            for open items.
          nullable: true
        result:
          type: object
        rowsDeleted:
          type: integer
          format: int64
          nullable: true
        rowsDiscovered:
          type: integer
          format: int64
          nullable: true
        rowsFailed:
          type: integer
          format: int64
          nullable: true
        rowsInserted:
          type: integer
          format: int64
          nullable: true
        rowsUpdated:
          type: integer
          format: int64
          nullable: true
        rowsValid:
          type: integer
          format: int64
          nullable: true
        sampleErrors:
          type: array
          description: "Up to 100 line-level errors, 'line N: message', once the import\
            \ ran."
          items:
            type: string
            description: "Up to 100 line-level errors, 'line N: message', once the\
              \ import ran."
        startedAt:
          type: string
          format: date-time
          nullable: true
        status:
          type: string
          description: queued | running | succeeded | failed.
          example: queued
        year:
          type: integer
          format: int32
          description: The accounting year the data belongs to; absent for company-scoped
            kinds.
          nullable: true
    JobResponse:
      type: object
      description: "An asynchronous job. Poll GET /v1/jobs/{jobId} until status is\
        \ terminal."
      properties:
        createdAt:
          type: string
          format: date-time
        error:
          type: string
          description: "Failure summary, present when status is failed."
          nullable: true
        finishedAt:
          type: string
          format: date-time
          nullable: true
        id:
          type: string
          format: uuid
          description: The job's stable identifier.
        params:
          type: object
        result:
          type: object
        startedAt:
          type: string
          format: date-time
          nullable: true
        status:
          type: string
          description: pending | running | succeeded | failed | expired.
          example: pending
        type:
          type: string
          description: The job type.
          example: document_export
    LedgerAccountResponse:
      type: object
      description: An account in the company's chart of accounts for one accounting
        year.
      properties:
        accountNumber:
          type: string
          description: The account number as it exists in the ERP.
          example: "3000"
        category:
          type: string
          description: ERP-supplied category.
          nullable: true
        currencyCode:
          type: string
          description: Account currency.
          example: NOK
          nullable: true
        hasActivity:
          type: boolean
          description: Whether the account has any GL activity this year.
        name:
          type: string
          description: Account name.
          example: "Salgsinntekt, avgiftspliktig"
          nullable: true
        saftCode:
          type: string
          description: "The mapped Norwegian SAF-T standard account code, when mapped."
          example: "3000"
          nullable: true
        year:
          type: integer
          format: int32
          description: The accounting year this chart belongs to.
          example: 2026
    MasterDataResponse:
      type: object
      description: "A dimension value or a sub-ledger, identified by its company-wide\
        \ key."
      properties:
        description:
          type: string
          nullable: true
        key:
          type: string
          description: "The stable, company-wide key."
          example: DEPT-10
        parentKey:
          type: string
          description: "The parent's key, for hierarchies."
          nullable: true
        type:
          type: string
          description: A free-form type label.
          example: department
          nullable: true
        value:
          type: string
          description: The display value.
          example: Sales
    MasterLine:
      type: object
      description: One dimension value or sub-ledger of the company.
      properties:
        description:
          type: string
          nullable: true
        key:
          type: string
          description: "The stable key (department code, customer number, ...)."
          example: DEPT-10
        parentKey:
          type: string
          description: "The parent's key, for hierarchies."
          nullable: true
        type:
          type: string
          description: A free-form type label.
          example: department
          nullable: true
        value:
          type: string
          description: The display value.
          example: Sales
    OpenItemsImportRequest:
      type: object
      properties:
        fromDate:
          type: string
          format: date
          nullable: true
        items:
          type: array
          description: "Open items in the import contract's shape (itemKey, subLedgerKey,\
            \ subLedgerType, accountCode, documentId, entryCategory, documentDate,\
            \ amount, amountOpen, settlementStatus, optional documentNo, dueDate,\
            \ settledDate, currencyCode, transactionAmount, transactionAmountOpen,\
            \ transactionCurrencyCode, sourceDeleted, description, matches[])."
          items:
            type: object
        mode:
          type: string
          example: incremental
        subLedgerType:
          type: string
          example: customer
        toDate:
          type: string
          format: date
          nullable: true
    OpeningBalanceLine:
      type: object
      description: One opening-balance row of an account.
      properties:
        accountCode:
          type: string
          example: "1920"
        amount:
          type: number
          description: "Signed amount in the company's base currency, as a decimal\
            \ string."
          example: 125000.0
        description:
          type: string
          nullable: true
        dimensionKeys:
          type: array
          items:
            type: string
            nullable: true
          nullable: true
        exchangeRate:
          type: number
          nullable: true
        id:
          type: string
          description: Your stable id for this row; re-sending the same id updates
            it.
          example: OB-1920
        subLedgerKeys:
          type: array
          items:
            type: string
            nullable: true
          nullable: true
        transactionAmount:
          type: number
          nullable: true
        transactionCurrencyCode:
          type: string
          example: EUR
          nullable: true
    OpeningBalancesImportRequest:
      type: object
      properties:
        lines:
          type: array
          items:
            $ref: "#/components/schemas/OpeningBalanceLine"
        year:
          type: integer
          format: int32
    PageAccessPolicyResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AccessPolicyResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageBankAccount:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BankAccount"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageBankTransaction:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BankTransaction"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageCompanyResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CompanyResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageDocumentResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DocumentResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageGlLineResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/GlLineResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageImportResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ImportResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageLedgerAccountResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/LedgerAccountResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageMasterDataResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/MasterDataResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageReconciliation:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Reconciliation"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageUserResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/UserResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageVatTermResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/VatTermResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageWebhookDeliveryResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDeliveryResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    PageWebhookEndpointResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WebhookEndpointResponse"
        pagination:
          $ref: "#/components/schemas/Pagination"
    Pagination:
      type: object
      properties:
        has_more:
          type: boolean
        next_cursor:
          type: string
    PeriodMovement:
      type: object
      description: The movement of one fiscal period.
      properties:
        amount:
          type: number
        period:
          type: integer
          format: int32
          description: Fiscal period 1–12.
    PeriodSummary:
      type: object
      description: One period's state.
      properties:
        approvalStatus:
          type: string
          description: "The firm's period approval on the mapped GL account: APPROVED\
            \ | STALE | REVOKED; null = not approved (or no GL mapping)."
          nullable: true
        bankEntryCount:
          type: integer
          format: int32
        glEntryCount:
          type: integer
          format: int32
        groupCount:
          type: integer
          format: int32
        hasStale:
          type: boolean
          description: Any group in the period has gone stale.
        period:
          type: integer
          format: int32
    Problem:
      type: object
      description: RFC 9457 problem document — the shape of every error response.
        The `error` property carries the stable machine code from the error catalog.
      properties:
        detail:
          type: string
          description: Human-readable specifics
        error:
          type: string
          description: Stable machine code (see the error catalog)
        instance:
          type: string
        requestId:
          type: string
          description: Echo in support requests — it indexes the logs
        status:
          type: integer
        title:
          type: string
        type:
          type: string
          description: URI ending in the error's catalog slug
    Reconciliation:
      type: object
      description: "A reconciliation group: bank transactions matched against GL lines\
        \ for one period."
      properties:
        bankAccountId:
          type: string
          format: uuid
        bankAmountTotal:
          type: number
          description: Snapshot of the bank side at match time.
        bankEntries:
          type: array
          items:
            $ref: "#/components/schemas/BankEntry"
        createdAt:
          type: string
          format: date-time
        glAmountTotal:
          type: number
          description: Snapshot of the GL side at match time.
        glEntries:
          type: array
          items:
            $ref: "#/components/schemas/GlEntry"
        id:
          type: string
          format: uuid
        note:
          type: string
          nullable: true
        period:
          type: integer
          format: int32
          description: Fiscal period 1-12.
        periodYear:
          type: integer
          format: int32
        stale:
          type: boolean
          description: True when matched data changed after matching (either side).
    ReconciliationDeletionResult:
      type: object
      description: "Confirmation: the group is dissolved; its transactions and lines\
        \ are unreconciled again."
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          example: deleted
    ReconciliationSummary:
      type: object
      description: The reconciliation picture for one bank account across a year.
      properties:
        bankAccountId:
          type: string
          format: uuid
        periods:
          type: array
          items:
            $ref: "#/components/schemas/PeriodSummary"
        year:
          type: integer
          format: int32
    RenameRequest:
      type: object
      properties:
        displayName:
          type: string
    Rule:
      type: object
      description: "One rule: a role on one company, or on every company (companyId\
        \ null)."
      properties:
        accountIds:
          type: array
          description: Account ids when accountScope is SPECIFIED; empty otherwise.
          items:
            type: string
            format: uuid
            description: Account ids when accountScope is SPECIFIED; empty otherwise.
        accountScope:
          type: string
          description: ALL or SPECIFIED.
          example: ALL
        companyId:
          type: string
          format: uuid
          description: The company; null = every company in the organization.
          nullable: true
        role:
          type: string
          description: "VIEWER, AUDITOR, ACCOUNTANT or ADMIN."
          example: ACCOUNTANT
    RuleInput:
      type: object
      description: One rule of a policy document.
      properties:
        accountIds:
          type: array
          items:
            type: string
            format: uuid
          nullable: true
        accountScope:
          type: string
          nullable: true
        companyId:
          type: string
          format: uuid
          description: The company; null = every company in the organization.
          nullable: true
        role:
          type: string
    SubLedgersImportRequest:
      type: object
      properties:
        subLedgers:
          type: array
          items:
            $ref: "#/components/schemas/MasterLine"
    TrialBalanceAccount:
      type: object
      description: "One account's opening balance, monthly movements, and closing\
        \ balance."
      properties:
        accountNumber:
          type: string
          example: "3000"
        category:
          type: string
          nullable: true
        closingBalance:
          type: number
          description: Balance at the end of the year.
        name:
          type: string
          nullable: true
        openingBalance:
          type: number
          description: Balance at the start of the year.
        periods:
          type: array
          description: Monthly movements (NOT running balances).
          items:
            $ref: "#/components/schemas/PeriodMovement"
    TrialBalanceResponse:
      type: object
      description: Trial balance for one accounting year.
      properties:
        accounts:
          type: array
          items:
            $ref: "#/components/schemas/TrialBalanceAccount"
        companyId:
          type: string
          format: uuid
          description: The company.
        ledgerId:
          type: string
          format: uuid
          description: The ledger this balance was read from (one per company × year).
        totals:
          $ref: "#/components/schemas/TrialBalanceTotals"
        year:
          type: integer
          format: int32
          description: Accounting year.
    TrialBalanceTotals:
      type: object
      description: Sums across all accounts.
      properties:
        closingBalance:
          type: number
        openingBalance:
          type: number
    UpdateCompanyRequest:
      type: object
      properties:
        companyNumber:
          type: string
          nullable: true
        companyType:
          type: string
          nullable: true
        countryCode:
          type: string
          nullable: true
        fiscalYearEnd:
          type: string
          format: date
          nullable: true
        fiscalYearStart:
          type: string
          format: date
          nullable: true
        name:
          type: string
          nullable: true
        periodType:
          type: string
          nullable: true
    UpdatePolicyRequest:
      type: object
      properties:
        description:
          type: string
          nullable: true
        isDefault:
          type: boolean
          nullable: true
        name:
          type: string
          nullable: true
        rules:
          type: array
          items:
            $ref: "#/components/schemas/RuleInput"
          nullable: true
    UpdateWebhookRequest:
      type: object
      properties:
        description:
          type: string
          nullable: true
        eventTypes:
          type: array
          items:
            type: string
          nullable: true
        url:
          type: string
          nullable: true
    Upload:
      type: object
      description: "Where and how to upload the binary — directly to storage, not\
        \ through the API."
      properties:
        contentType:
          type: string
          description: The Content-Type header the PUT must carry (it is part of the
            signature).
        expiresAt:
          type: string
          format: date-time
        method:
          type: string
          example: PUT
        url:
          type: string
          description: Signed PUT URL for the binary.
    UserResponse:
      type: object
      description: A user of the organization.
      properties:
        createdAt:
          type: string
          format: date-time
          description: When the user was registered.
          nullable: true
        email:
          type: string
          nullable: true
        firstName:
          type: string
          nullable: true
        id:
          type: string
          format: uuid
          description: The user's stable identifier.
        lastName:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        role:
          type: string
          description: Membership role in this organization.
          example: MEMBER
        status:
          type: string
          description: "Lifecycle state: 'active' or 'disabled'."
          example: active
    VatTermResponse:
      type: object
      description: A VAT filing term and its current status.
      properties:
        calculatedTotal:
          type: number
          description: Calculated VAT total for the term (NOK).
          nullable: true
        difference:
          type: number
          description: calculated − filed (NOK).
          nullable: true
        filedTotal:
          type: number
          description: Filed VAT total per the tax authority (NOK).
          nullable: true
        id:
          type: string
          format: uuid
          description: The term's stable identifier.
        periodEnd:
          type: string
          format: date
          description: Last day of the term.
          nullable: true
        periodStart:
          type: string
          format: date
          description: First day of the term.
          nullable: true
        sequence:
          type: integer
          format: int32
          description: Term sequence within the year (1-based).
          example: 3
        status:
          type: string
          description: "Reconciliation status. Common values: approved_for_sending,\
            \ sent_to_egov, approved, reopened; earlier worker-side statuses may also\
            \ appear."
          nullable: true
        year:
          type: integer
          format: int32
          description: Filing year.
          example: 2026
    WebhookDeliveryResponse:
      type: object
      description: One delivery attempt log for an endpoint (self-debugging surface).
      properties:
        attempts:
          type: integer
          format: int32
        createdAt:
          type: string
          format: date-time
        deliveredAt:
          type: string
          format: date-time
          nullable: true
        eventId:
          type: string
          format: uuid
          description: The event this delivery carries — dedupe on this.
        eventType:
          type: string
        id:
          type: string
          format: uuid
          description: The delivery's identifier (retries share it).
        lastError:
          type: string
          nullable: true
        lastStatusCode:
          type: integer
          format: int32
          nullable: true
        payload:
          type: object
        status:
          type: string
          description: pending | delivered | dead.
          example: delivered
    WebhookEndpointCreatedResponse:
      type: object
      description: A newly registered (or secret-rotated) endpoint. The secret appears
        ONLY here — store it now.
      properties:
        endpoint:
          $ref: "#/components/schemas/WebhookEndpointResponse"
        secret:
          type: string
          description: The HMAC signing secret. Shown exactly once; rotate to get
            a new one.
    WebhookEndpointDeletionResult:
      type: object
      description: Confirmation of endpoint deletion.
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          example: deleted
    WebhookEndpointResponse:
      type: object
      description: A webhook endpoint registration.
      properties:
        createdAt:
          type: string
          format: date-time
        description:
          type: string
          nullable: true
        disabledReason:
          type: string
          description: "Why the endpoint was disabled, when status is disabled."
          nullable: true
        eventTypes:
          type: array
          description: Subscribed event types; empty = every event type.
          items:
            type: string
            description: Subscribed event types; empty = every event type.
        id:
          type: string
          format: uuid
          description: The endpoint's stable identifier.
        status:
          type: string
          description: pending_verification | active | disabled. New endpoints must
            answer the verification challenge before deliveries start; repeated delivery
            failure auto-disables an endpoint.
          example: active
        url:
          type: string
    WhoamiResponse:
      type: object
      description: The authenticated principal's identity and scope.
      properties:
        clientId:
          type: string
          description: The integration's client id (the token's azp).
          example: com.acme.erp-sync
        mode:
          type: string
          description: "How this principal acts: SYSTEM, USER (headless, as its linked\
            \ human), or INTERACTIVE (a person, e.g. via an MCP client)."
          example: SYSTEM
        organizationId:
          type: string
          format: uuid
          description: The organization whose subtree this client reaches. Null for
            INTERACTIVE principals — a person's reach is their org memberships.
          nullable: true
        organizationIds:
          type: array
          description: "For INTERACTIVE principals, the organizations the person belongs\
            \ to — the tenants their calls can reach. Null for machine clients, whose\
            \ single organization is organizationId."
          items:
            type: string
            format: uuid
            description: "For INTERACTIVE principals, the organizations the person\
              \ belongs to — the tenants their calls can reach. Null for machine clients,\
              \ whose single organization is organizationId."
            nullable: true
          nullable: true
        userId:
          type: string
          format: uuid
          description: "The human every check runs as: the linked user for USER mode,\
            \ the signed-in person for INTERACTIVE. Null for SYSTEM — a machine acts\
            \ as itself."
          nullable: true
    Year:
      type: object
      description: What one accounting year's ledger holds.
      properties:
        accounts:
          type: integer
          format: int64
        current:
          type: boolean
          description: Whether this is the company's current accounting year.
        generalLedgerLines:
          type: integer
          format: int64
        lastImportAt:
          type: string
          format: date-time
          description: When the latest successful import or correction for this year
            finished.
          nullable: true
        mappedAccounts:
          type: integer
          format: int64
          description: Accounts mapped to a standard account.
        openingBalances:
          type: integer
          format: int64
        year:
          type: integer
          format: int32
  securitySchemes:
    oauth2:
      description: "OAuth 2.0 client credentials against the Accountflow Keycloak\
        \ realm. Exchange your API client's id and secret for a bearer token (see\
        \ Authentication), then send it on every request. What the token may do comes\
        \ from the scopes granted when the client was provisioned, not from the token\
        \ request."
      flows:
        clientCredentials:
          scopes:
            access:manage: Manage access policies
            bank:read: Read bank data
            companies:read: Read companies
            companies:write: Manage companies
            documents:read: Read documents
            documents:write: Manage documents
            imports:write: Push and correct ledger data for API-managed companies
            ledger:read: "Read GL, accounts, trial balances"
            reconciliation:read: Read reconciliation status
            reconciliation:write: Work with reconciliations
            users:read: Read organization users
            vat:read: Read VAT status and returns
            webhooks:manage: Manage webhook endpoints
          tokenUrl: https://auth.lab.accountflow.com/realms/accountflow/protocol/openid-connect/token
      type: oauth2
