{
  "openapi": "3.1.0",
  "info": {
    "title": "Lintel API",
    "version": "1.21.0",
    "description": "Norsk regnskapssystem-backend. **Kun API.** Multi-tenant + multi-company, append-only hovedbok, balanserte posteringer, bilagsnummer uten hull, idempotens på alle mutasjoner, full audit trail.\n\n## Autentisering og kontekst\n\n- **Identitet**: alle endepunkter krever `Authorization: Bearer <access_token>` (Supabase-JWT). Kun `/v1/auth/*` og `/v1/invitations/{token}` (GET) er unntatt.\n- **Aktiv tenant (`X-Tenant-Id`)**: prinsipal = (bruker, tenant). Klienten *bør* sende `X-Tenant-Id` på alle autentiserte kall. Serveren utleder automatisk når brukeren kun har ett medlemskap. Er brukeren medlem av flere tenants og headeren mangler, returneres `409 ambiguous_tenant` med `extensions.candidates` (liste over tenants brukeren kan velge). Peker headeren på en tenant brukeren ikke tilhører, returneres `403 tenant_forbidden`.\n- **Aktivt selskap**: selskapsscopede endepunkter tar `{company_id}` (dokumentasjonsnavn — path-parameter kalles `{id}` i gjeldende revisjon) i URL. Tilgang krever en `company_members`-rad i den aktive tenanten (ADR-014) — tenant-rolle gir ingen implisitt selskapstilgang.\n\n## Personlig vs delt tenant (ADR-016)\n\n- Alle brukere får én **personlig tenant** (`kind='personal'`) ved signup. Personlige tenants kan **ikke** deles: nye medlemmer, invitasjoner, delegerte selskaper og innkommende eierskifter blokkeres av både API-lag (`409 personal_tenant`) og databasetriggere (`personal_tenant_no_sharing`).\n- **Delte tenants** (`kind='shared'`, typisk regnskapsbyrå) opprettes eksplisitt via `POST /v1/tenants`. Kaller blir første `owner`. Delte tenants kan invitere medlemmer og eie/motta selskaper som normalt.\n- `kind` returneres i `GET /v1/auth/tenants` og er låst etter opprettelse.\n\n## Idempotens\n\n- **Regel**: alle POST-endepunkter som *oppretter en ressurs eller utfører en handling* aksepterer `Idempotency-Key` (UUID). Nøkkelen er dokumentert som anbefalt (`required: false`). Samme nøkkel + samme body innen 24 t returnerer det cachede svaret; samme nøkkel + endret body → `409 idempotency_key_conflict`.\n- **PATCH/PUT/DELETE** er naturlig idempotente og skal *ikke* sende `Idempotency-Key`.\n- **Unntak**: auth-endepunktene (`/v1/auth/signup|login|logout|refresh|forgot-password`) og `POST /api/mcp` (JSON-RPC har egen id).\n\n## Feilmodell (RFC 7807)\n\nAlle feil returneres som `application/problem+json` med feltene `type`, `title`, `status`, `detail`, valgfri `instance` og `trace_id` (uuid — request-id fra edge-runtime, gjenta i supportsaker). Kjente `type`-verdier:\n\n| type | Betydning |\n|---|---|\n| `unauthorized` | 401 — token mangler eller er ugyldig |\n| `forbidden` | 403 — mangler rolle/tilgang |\n| `tenant_forbidden` | 403 — `X-Tenant-Id` peker på tenant brukeren ikke er medlem av |\n| `ambiguous_tenant` | 409 — flere tenants, ingen header. `extensions.candidates` gir valg |\n| `personal_tenant` | 409 — handlingen er ikke tillatt på en personlig tenant (invitasjon, eierskifte, member-fjerning) |\n| `no_tenant` | 403 — bruker er ikke medlem av noen tenant |\n| `tenant_pending_approval` | 403 — byråkontoen venter på manuell godkjenning |\n| `tenant_rejected` | 403 — byråkontoen er avvist |\n| `not_found` | 404 — ressurs finnes ikke eller ikke tilgjengelig |\n| `invalid_body` / `invalid_query` | 400 — validering |\n| `invalid_ledger_line` | 400 — bilagslinje blander NOK-variant (`debit_nok`/`credit_nok`) med valutavariant (`amount`/`currency`) |\n| `invalid_state` | 422 — ressursen er i feil status for handlingen |\n| `period_closed` | 422 — perioden er lukket |\n| `not_balanced` | 422 — postering ikke i balanse |\n| `party_mismatch` / `ledger_type_mismatch` / `currency_mismatch` | 422 — kolliderende reskontro-egenskaper |\n| `fully_paid` / `overpayment` | 422 — betalingsreglene |\n| `last_owner` | 409 — kan ikke fjerne den siste owner-brukeren i eier-tenanten |\n| `transfer_expired_or_resolved` | 410 — eierskifte-token utløpt eller allerede løst |\n| `missing_idempotency_key` / `idempotency_key_conflict` | 400/409 — idempotens |\n| `duplicate_org_number` / `duplicate_account_number` | 409 — unik-constraint |\n\n## Natural keys (ADR-013)\n\nBilagslinjer refererer kontoen med **kontonummer** (`account_number`), ikke intern UUID. Perioden avledes automatisk fra `voucher_date`. Reskontroparten refereres med `party_id`, men `invoice_number` og `external_ref` er de menneskelige matchnøklene.\n\n## Bilagslinjer: brutto/MVA-semantikk\n\nNår `vat_code` er satt og koden har rate > 0, tolkes beløpsfeltene som **brutto** (inkl. mva). Server splitter automatisk ut mva-beløpet på mva-kontoen definert i selskapets kontoplan (typisk 2710 for inngående 25%). Reskontro- og bank-linjer skal alltid være brutto og bør ikke ha `vat_code`.\n\n## Handlings-endepunkter\n\nHandlinger utover CRUD bruker et verb-suffiks på ressurs-URL-en: `/pay`, `/reverse`, `/close`, `/reopen`, `/accept`, `/decline`, `/approve`, `/submit`, `/refresh`, `/resign`, `/cancel`, `/match`, `/ignore`, `/post`, `/send`, `/sync`, `/auto-match`, `/learn`. Se `operationId` på hver operasjon for det kanoniske navnet i klientkoden.\n\n## Liste-envelope\n\nListeendepunkter bruker query-parametrene `limit` (1–500, default 50) og `offset` (default 0). Svaret er en `Paginated<T>`-konvolutt med felles `PaginationMeta` (`total_count`, `limit`, `offset`) og en typet `data`- (eller ressurs-spesifikk) array."
  },
  "servers": [
    {
      "url": "https://erpapi.lovable.app",
      "description": "Produksjon"
    },
    {
      "url": "/",
      "description": "This deployment"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      },
      "supabaseApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "apikey",
        "description": "Supabase anon-nøkkel. Påkrevd for /auth/v1/* (signup, signin, refresh, logout). Sett `apikey` til prosjektets publishable/anon key."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "Anbefalt UUID. Samme nøkkel + samme body innen 24 t = cachet svar. Utelatt = ingen replay-beskyttelse. Ulik body med samme nøkkel → 409 idempotency_key_conflict."
      },
      "XTenantId": {
        "name": "X-Tenant-Id",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "ADR-014: velger aktiv tenant per request. Kreves når brukeren tilhører flere tenants — mangler headeren, returneres `409 ambiguous_tenant` med kandidatliste. Peker på en tenant brukeren ikke er medlem av → `403 tenant_forbidden`."
      },
      "PsuIpAddress": {
        "name": "PSU-IP-Address",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "description": "IPv4 eller IPv6"
        },
        "description": "PSD2: IP-adressen til sluttbrukeren som utløser handlingen i nettleseren. **Må være brukerens reelle IP**, ikke serverens. Hent fra første verdi i `X-Forwarded-For` på den innkommende requesten i frontend/proxy og videresend hit. ZTL bruker denne til risikovurdering og BankID/SCA, og banker rate-limiter kall uten korrekt PSU-info til ~4/dag."
      },
      "PsuUserAgent": {
        "name": "PSU-User-Agent",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "PSD2: `User-Agent` fra sluttbrukerens nettleser. Send alltid sammen med `PSU-IP-Address` når brukeren er til stede."
      },
      "CompanyId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "Selskaps-ID (auto-fylt fra valgt selskap i toppen)."
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 500,
          "default": 50
        },
        "description": "Maks antall rader i svaret."
      },
      "Offset": {
        "name": "offset",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 0,
          "default": 0
        },
        "description": "Antall rader å hoppe over (for paginering)."
      },
      "LedgerTypeQuery": {
        "name": "ledger_type",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "AR",
            "AP",
            "both"
          ],
          "default": "both"
        },
        "description": "AR = kundereskontro, AP = leverandørreskontro, both = alle reskontroposter."
      }
    },
    "responses": {
      "Problem": {
        "description": "Feil. RFC 7807 problem+json.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Mangler eller ugyldig Bearer-token.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Autentisert, men mangler rolle/tilgang.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "NotFound": {
        "description": "Ressurs ikke funnet.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "NoContent": {
        "description": "Suksess — ingen body."
      },
      "TenantForbidden": {
        "description": "`X-Tenant-Id` peker på en tenant brukeren ikke er medlem av.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/TenantForbiddenProblem"
            }
          }
        }
      },
      "AmbiguousTenant": {
        "description": "Brukeren tilhører flere tenants og `X-Tenant-Id` mangler. `extensions.candidates` lister mulige tenants.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/AmbiguousTenantProblem"
            }
          }
        }
      },
      "LastOwner": {
        "description": "Kan ikke fjerne den siste `owner`-brukeren for selskapet i eier-tenanten.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/LastOwnerProblem"
            }
          }
        }
      },
      "TransferExpiredOrResolved": {
        "description": "Eierskifte-token er utløpt eller allerede løst.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/TransferExpiredOrResolvedProblem"
            }
          }
        }
      }
    },
    "schemas": {
      "FinanstilsynetSearchResult": {
        "type": "object",
        "description": "Treffliste fra Finanstilsynets verksemdsregister, filtrert på autoriserte regnskapsselskaper (lisenstype REGS).",
        "required": [
          "results",
          "total_count"
        ],
        "properties": {
          "total_count": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "org_number": {
                  "type": "string",
                  "nullable": true
                },
                "name": {
                  "type": "string",
                  "nullable": true
                },
                "org_form": {
                  "type": "string",
                  "nullable": true
                },
                "address_line1": {
                  "type": "string",
                  "nullable": true
                },
                "address_line2": {
                  "type": "string",
                  "nullable": true
                },
                "postal_code": {
                  "type": "string",
                  "nullable": true
                },
                "city": {
                  "type": "string",
                  "nullable": true
                },
                "country_code": {
                  "type": "string",
                  "nullable": true
                },
                "website": {
                  "type": "string",
                  "nullable": true
                },
                "finanstilsynet_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "Finanstilsynets interne ID for virksomheten."
                },
                "licence_types": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Alle lisenstyper virksomheten har, f.eks. `REGS`."
                },
                "licence_registered_at": {
                  "type": "string",
                  "format": "date",
                  "nullable": true,
                  "description": "Dato REGS-lisensen ble registrert."
                },
                "authorized_accounting_firm": {
                  "type": "boolean",
                  "description": "Alltid true i svaret; treffene er filtrert på REGS."
                }
              }
            }
          }
        }
      },
      "Tenant": {
        "type": "object",
        "description": "En tenant er arbeidsområdet man jobber i — typisk et regnskapsbyrå (`kind='shared'`) eller brukerens personlige område (`kind='personal'`). Profilfeltene brukes bl.a. i kvalitetssikringsflyten og på rapporter.",
        "required": [
          "id",
          "name",
          "kind",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Navn på byrået/arbeidsområdet."
          },
          "kind": {
            "type": "string",
            "enum": [
              "personal",
              "shared"
            ]
          },
          "org_number": {
            "type": "string",
            "nullable": true,
            "description": "Organisasjonsnummer. Normaliseres til kun siffer."
          },
          "logo_url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Absolutt URL til byråets logo."
          },
          "address_line1": {
            "type": "string",
            "nullable": true
          },
          "address_line2": {
            "type": "string",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "nullable": true
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "country_code": {
            "type": "string",
            "nullable": true,
            "description": "ISO 3166-1 alpha-2, f.eks. `NO`."
          },
          "email": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "website": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "note": {
            "type": "string",
            "nullable": true,
            "description": "Fritekst, f.eks. interne rutiner for kvalitetssikring."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ],
            "description": "ADR-021: godkjenningsstatus. Nye delte tenants (byråkontoer) opprettes som `pending` og må godkjennes manuelt før de kan brukes. Personlige tenants er alltid `approved`."
          },
          "approved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "rejection_reason": {
            "type": "string",
            "nullable": true,
            "description": "Satt når `status = 'rejected'`."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "TenantProfileInput": {
        "type": "object",
        "description": "Profilfelter for en tenant. Alle er valgfrie; send `null` for å nullstille et felt.",
        "properties": {
          "org_number": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "logo_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2000,
            "nullable": true
          },
          "address_line1": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "address_line2": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "maxLength": 20,
            "nullable": true
          },
          "city": {
            "type": "string",
            "maxLength": 100,
            "nullable": true
          },
          "country_code": {
            "type": "string",
            "maxLength": 2,
            "nullable": true
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 200,
            "nullable": true
          },
          "phone": {
            "type": "string",
            "maxLength": 40,
            "nullable": true
          },
          "website": {
            "type": "string",
            "format": "uri",
            "maxLength": 2000,
            "nullable": true
          },
          "note": {
            "type": "string",
            "maxLength": 2000,
            "nullable": true
          }
        }
      },
      "AppOrigin": {
        "type": "object",
        "description": "Godkjent redirect-origin for e-postlenker (ADR-020).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "origin": {
            "type": "string",
            "format": "uri",
            "example": "https://app.kunde.no"
          },
          "label": {
            "type": "string",
            "nullable": true
          },
          "created_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "description": "RFC 7807 feilformat. `error.{code,message}` er beholdt for bakoverkompatibilitet.",
        "required": [
          "type",
          "title",
          "status"
        ],
        "properties": {
          "type": {
            "type": "string",
            "description": "Maskinlesbar feilkode, f.eks. `validation_error`."
          },
          "title": {
            "type": "string",
            "description": "Kort, menneskelesbar tittel."
          },
          "status": {
            "type": "integer",
            "description": "HTTP statuskode."
          },
          "detail": {
            "type": "string",
            "description": "Detaljert forklaring."
          },
          "instance": {
            "type": "string",
            "description": "URI som identifiserer hendelsen (valgfri)."
          },
          "error": {
            "type": "object",
            "description": "Legacy-felt — ikke bruk i ny kode.",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "trace_id": {
            "type": "string",
            "format": "uuid",
            "description": "Request-id fra edge-runtime. Gjenta i supportsaker."
          }
        }
      },
      "TenantForbiddenProblem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProblemDetails"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "const": "tenant_forbidden"
              },
              "status": {
                "const": 403
              }
            }
          }
        ]
      },
      "AmbiguousTenantProblem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProblemDetails"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "const": "ambiguous_tenant"
              },
              "status": {
                "const": 409
              },
              "candidates": {
                "type": "array",
                "description": "Tenants brukeren tilhører. Velg én og send som `X-Tenant-Id`.",
                "items": {
                  "type": "object",
                  "required": [
                    "tenant_id",
                    "tenant_name",
                    "role"
                  ],
                  "properties": {
                    "tenant_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "tenant_name": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "LastOwnerProblem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProblemDetails"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "const": "last_owner"
              },
              "status": {
                "const": 409
              }
            }
          }
        ]
      },
      "TransferExpiredOrResolvedProblem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProblemDetails"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "const": "transfer_expired_or_resolved"
              },
              "status": {
                "const": 410
              }
            }
          }
        ]
      },
      "Membership": {
        "type": "object",
        "required": [
          "tenant_id",
          "tenant_name",
          "kind",
          "role",
          "companies"
        ],
        "properties": {
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "personal",
              "shared"
            ],
            "description": "ADR-016: `personal` = brukerens private tenant (kan ikke deles). `shared` = delt arbeidsområde."
          },
          "tenant_kind": {
            "type": "string",
            "enum": [
              "personal",
              "shared"
            ],
            "description": "Alias for `kind` (bakoverkompatibelt feltnavn)."
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "accountant",
              "bookkeeper",
              "viewer"
            ]
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "company_count": {
            "type": "integer",
            "description": "Alltid lik `companies.length`."
          },
          "companies": {
            "type": "array",
            "description": "Alle selskaper brukeren har tilgang til i tenanten: union av eksplisitte `company_members`-rader og — når tenant-rollen er `owner` — alle selskaper koblet til tenanten. Identisk sett som GET /v1/companies med samme X-Tenant-Id.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "role"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "org_number": {
                  "type": "string",
                  "nullable": true
                },
                "role": {
                  "type": "string",
                  "enum": [
                    "owner",
                    "accountant",
                    "bookkeeper",
                    "viewer"
                  ]
                },
                "relationship": {
                  "type": "string",
                  "enum": [
                    "owner",
                    "delegated"
                  ],
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "MembershipsResponse": {
        "type": "object",
        "required": [
          "memberships",
          "total_count"
        ],
        "properties": {
          "memberships": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Membership"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "pending_invitations": {
            "type": "integer",
            "description": "Antall åpne, ikke-utløpte invitasjoner til brukerens e-post. Brukes til onboarding når `memberships` er tom."
          }
        }
      },
      "OwnershipTransfer": {
        "type": "object",
        "required": [
          "id",
          "company_id",
          "from_tenant_id",
          "to_tenant_id",
          "expires_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "from_tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "to_tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "initiated_by": {
            "type": "string",
            "format": "uuid"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "outcome": {
            "type": "string",
            "enum": [
              "accepted",
              "declined"
            ],
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OwnershipTransferListResponse": {
        "type": "object",
        "required": [
          "transfers",
          "total_count"
        ],
        "properties": {
          "transfers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OwnershipTransfer"
            }
          },
          "total_count": {
            "type": "integer"
          }
        }
      },
      "CompanyMember": {
        "type": "object",
        "required": [
          "user_id",
          "tenant_id",
          "company_id",
          "role"
        ],
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "accountant",
              "bookkeeper",
              "viewer"
            ]
          },
          "email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "description": "Brukerens e-post fra auth.users. Kun satt på listeendepunkter (GET)."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Fullt navn fra user_metadata (full_name / name). Kun satt på listeendepunkter (GET)."
          },
          "company_role": {
            "type": "string",
            "nullable": true,
            "enum": [
              "owner",
              "accountant",
              "bookkeeper",
              "viewer",
              null
            ],
            "description": "Effektiv rolle på selskapet (fra company_members). Null hvis medlemmet ikke har eksplisitt selskaps­tilgang."
          },
          "has_company_access": {
            "type": "boolean",
            "description": "True hvis det finnes en company_members-rad for (user, tenant, company)."
          }
        }
      },
      "CompanyGrant": {
        "type": "object",
        "required": [
          "company_id",
          "role"
        ],
        "properties": {
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "accountant",
              "bookkeeper",
              "viewer"
            ]
          }
        }
      },
      "VatCode": {
        "type": "object",
        "description": "ADR-019: selskaps-eid MVA-kode. `id` er autoritativ referanse, `code` er en mutbar etikett.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "example": "1"
          },
          "name": {
            "type": "string"
          },
          "rate": {
            "type": "number",
            "example": 25
          },
          "vat_type": {
            "type": "string",
            "enum": [
              "incoming",
              "outgoing",
              "reverse_charge",
              "none",
              "exempt"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "sort_order": {
            "type": "integer"
          },
          "vat_account_number": {
            "type": "string",
            "nullable": true
          },
          "reverse_charge_account_number": {
            "type": "string",
            "nullable": true
          },
          "deduction_rate": {
            "type": "number",
            "example": 100
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "in_use": {
            "type": "boolean",
            "description": "Kun garantert på GET-lista: true hvis koden er referert fra minst én bokført postering. Da er `rate`, `deduction_rate` og `vat_type` frosne (409 locked_usage ved endring)."
          }
        }
      },
      "OkResponse": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "required": [
          "total_count",
          "limit",
          "offset"
        ],
        "properties": {
          "total_count": {
            "type": "integer",
            "description": "Totalt antall matchende rader (uavhengig av limit/offset)."
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "Company": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "org_number": {
            "type": "string",
            "nullable": true
          },
          "functional_currency": {
            "type": "string",
            "example": "NOK"
          },
          "invoice_from_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "description": "Avsender-e-post for utgående salgsfakturaer."
          },
          "inbox_email_local": {
            "type": "string",
            "nullable": true,
            "description": "Lokal-del av Bilagsmottak-e-post (før @)."
          },
          "inbox_auto_post": {
            "type": "boolean",
            "default": false,
            "description": "Om innkommende fakturaer i Bilagsmottaket skal bokføres automatisk."
          },
          "address_line1": {
            "type": "string",
            "nullable": true
          },
          "address_line2": {
            "type": "string",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "nullable": true
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "account_number": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "account_type": {
            "type": "string",
            "enum": [
              "asset",
              "liability",
              "equity",
              "income",
              "expense"
            ]
          },
          "vat_code": {
            "type": "string",
            "nullable": true
          },
          "is_subledger": {
            "type": "boolean"
          },
          "ledger_type": {
            "type": "string",
            "enum": [
              "AR",
              "AP"
            ],
            "nullable": true
          },
          "is_system": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "Party": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "org_number": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "nullable": true
          },
          "city": {
            "type": "string",
            "nullable": true
          },
          "is_customer": {
            "type": "boolean"
          },
          "is_supplier": {
            "type": "boolean"
          },
          "ar_account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Koblet kundereskontrokonto (accounts)."
          },
          "ar_account_number": {
            "type": "string",
            "nullable": true
          },
          "ap_account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Koblet leverandørreskontrokonto (accounts)."
          },
          "ap_account_number": {
            "type": "string",
            "nullable": true
          },
          "role": {
            "type": "string",
            "enum": [
              "customer",
              "supplier",
              "both",
              "none"
            ],
            "nullable": true
          },
          "ar_open_total": {
            "type": "number",
            "nullable": true
          },
          "ap_open_total": {
            "type": "number",
            "nullable": true
          },
          "bank_account_number": {
            "type": "string",
            "nullable": true,
            "description": "Legacy: primær konto. Bruk party_bank_accounts."
          },
          "iban": {
            "type": "string",
            "nullable": true,
            "description": "Legacy."
          },
          "bic": {
            "type": "string",
            "nullable": true,
            "description": "Legacy."
          },
          "invoice_delivery_method": {
            "type": "string",
            "enum": [
              "manual",
              "email",
              "ehf"
            ],
            "description": "Foretrukken metode for å sende salgsfakturaer til denne parten."
          },
          "invoice_delivery_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "description": "E-postadresse for fakturasending. Påkrevd når invoice_delivery_method='email'."
          }
        }
      },
      "Period": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "fiscal_year_id": {
            "type": "string",
            "format": "uuid"
          },
          "fiscal_year": {
            "type": "integer"
          },
          "month": {
            "type": "integer",
            "minimum": 1,
            "maximum": 12
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "closed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "closed_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        }
      },
      "PeriodBrief": {
        "type": "object",
        "description": "Kortform av en periode brukt i gjenåpningssvar.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "period_number": {
            "type": "integer",
            "minimum": 1,
            "maximum": 12
          }
        }
      },
      "FiscalYear": {
        "type": "object",
        "description": "Regnskapsår med tilhørende månedsperioder.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "year": {
            "type": "integer"
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "partial",
              "closed",
              "empty"
            ],
            "description": "open = alle perioder åpne, partial = noen åpne/lukket, closed = alle lukket, empty = ingen perioder."
          },
          "periods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Period"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VoucherLine": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "voucher_id": {
            "type": "string",
            "format": "uuid"
          },
          "line_no": {
            "type": "integer"
          },
          "account_number": {
            "type": "string"
          },
          "debit_nok": {
            "type": "number"
          },
          "credit_nok": {
            "type": "number"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "fx_rate": {
            "type": "number"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "vat_code": {
            "type": "string",
            "nullable": true
          },
          "vat_amount_nok": {
            "type": "number",
            "nullable": true
          },
          "party_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "invoice_number": {
            "type": "string",
            "nullable": true
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "external_ref": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "VoucherRef": {
        "type": "object",
        "nullable": true,
        "description": "Kompakt referanse til bilaget fakturaen er bokført til. Null så lenge fakturaen er kladd.",
        "properties": {
          "voucher_number": {
            "type": "integer",
            "nullable": true
          },
          "voucher_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        }
      },
      "Voucher": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "voucher_number": {
            "type": "integer",
            "nullable": true,
            "description": "Tildeles ved bokføring."
          },
          "voucher_date": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "posted",
              "reversed"
            ]
          },
          "posted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "posted_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "reversed_by_voucher_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "period_id": {
            "type": "string",
            "format": "uuid"
          },
          "review_status": {
            "type": "string",
            "nullable": true,
            "enum": [
              "pending",
              "approved",
              "flagged",
              "rejected"
            ],
            "description": "Gjeldende kontrollstatus (denormalisert fra siste voucher_review). null = ukontrollert."
          },
          "review_reviewed_by_type": {
            "type": "string",
            "nullable": true,
            "enum": [
              "human",
              "ai"
            ]
          },
          "review_reviewed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "review_reviewed_by_user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "review_open_findings_count": {
            "type": "integer",
            "description": "Antall funn med severity warning/error i siste review."
          },
          "review": {
            "$ref": "#/components/schemas/VoucherReviewSummary"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VoucherLine"
            }
          }
        }
      },
      "SupplierInvoice": {
        "type": "object",
        "properties": {
          "posted_voucher_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Bilaget fakturaen er bokført til (= `voucher_id`). Null så lenge fakturaen er kladd. 1:1 – ett bilag kan kun eies av én faktura.",
            "readOnly": true
          },
          "voucher": {
            "$ref": "#/components/schemas/VoucherRef"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "supplier_id": {
            "type": "string",
            "format": "uuid"
          },
          "invoice_number": {
            "type": "string"
          },
          "invoice_date": {
            "type": "string",
            "format": "date"
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "currency": {
            "type": "string"
          },
          "total_amount": {
            "type": "number"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending_approval",
              "approved",
              "posted",
              "paid",
              "rejected"
            ]
          }
        }
      },
      "OpenPost": {
        "type": "object",
        "description": "Reskontropost med gjenstående beløp. `open_amount` og `status` er utledede felter: de beregnes av databasen ut fra utligningslinjene (`subledger_settlement_lines`) knyttet til posten, og kan ikke settes direkte.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Reskontropostens id — brukes som `subledger_entry_id` mot `/match`."
          },
          "party_id": {
            "type": "string",
            "format": "uuid"
          },
          "party_name": {
            "type": "string"
          },
          "ledger_type": {
            "type": "string",
            "enum": [
              "AR",
              "AP"
            ]
          },
          "invoice_number": {
            "type": "string",
            "nullable": true
          },
          "document_ref": {
            "type": "string",
            "nullable": true
          },
          "voucher_date": {
            "type": "string",
            "format": "date"
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "original_amount": {
            "type": "number"
          },
          "paid_amount": {
            "type": "number"
          },
          "open_amount": {
            "type": "number",
            "description": "Utledet: `original_amount − sum(applied_amount)`."
          },
          "settled_amount": {
            "type": "number",
            "description": "Utlignet så langt (`original_amount − open_amount`)."
          },
          "settlement_count": {
            "type": "integer",
            "description": "Antall utligningslinjer som treffer posten. 0 = urørt, >1 = flere delutligninger. Alltid lik `settlements.length`."
          },
          "settlements": {
            "type": "array",
            "description": "Utligningene posten inngår i, nyeste først. En post kan ha flere ved delbetalinger. `close_group_id` kan brukes mot `DELETE /v1/companies/{id}/match?close_group_id=…` for å oppheve nettopp den utligningen. Tom array hvis posten ikke er utlignet.",
            "items": {
              "type": "object",
              "properties": {
                "close_group_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "applied_amount": {
                  "type": "number",
                  "description": "Beløp anvendt mot posten i denne utligningen (streng med 2 desimaler)."
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "partial",
              "matched"
            ],
            "description": "Utledet. `partial` = delvis utlignet (0 < open_amount < original_amount)."
          },
          "days_overdue": {
            "type": "integer"
          }
        }
      },
      "CloseGroup": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "party_id": {
            "type": "string",
            "format": "uuid"
          },
          "closed_at": {
            "type": "string",
            "format": "date-time"
          },
          "closed_by": {
            "type": "string",
            "format": "uuid"
          },
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "voucher_line_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "amount": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "FxRate": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "example": "EUR"
          },
          "rate": {
            "type": "number",
            "description": "1 enhet av currency i NOK."
          },
          "rate_date": {
            "type": "string",
            "format": "date"
          },
          "source": {
            "type": "string",
            "example": "norges-bank"
          }
        }
      },
      "Member": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "accountant",
              "bookkeeper",
              "viewer"
            ]
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PaymentMethod": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "bank_account_number": {
            "type": "string"
          },
          "ztl_bank_account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "FK til ztl_bank_accounts."
          },
          "account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "FK til accounts (bankkonto i kontoplanen)."
          },
          "is_default": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "InboxItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "source": {
            "type": "string",
            "enum": [
              "email",
              "upload",
              "api"
            ]
          },
          "file_name": {
            "type": "string"
          },
          "file_url": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "matched",
              "archived"
            ]
          },
          "extracted": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          }
        }
      },
      "AuditLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "description": "E-post til brukeren som utførte handlingen."
          },
          "actor_name": {
            "type": "string",
            "nullable": true,
            "description": "Navn på brukeren (hentet fra user_metadata)."
          },
          "actor_source": {
            "type": "string",
            "nullable": true,
            "description": "F.eks. jwt, api_key, system, mcp."
          },
          "action": {
            "type": "string"
          },
          "resource_type": {
            "type": "string"
          },
          "resource_id": {
            "type": "string",
            "format": "uuid"
          },
          "summary": {
            "type": "string",
            "nullable": true,
            "description": "Menneskelesbar oppsummering av endringen."
          },
          "diff": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Endringer pr. felt: { field: { from, to } }."
          },
          "payload": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Hele request-body eller relevant kontekst."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedCompanies": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Company"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "PaginatedAccounts": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Account"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "PaginatedParties": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Party"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "PaginatedVouchers": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Voucher"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "ReviewFinding": {
        "type": "object",
        "required": [
          "severity",
          "code",
          "message"
        ],
        "properties": {
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warning",
              "error"
            ]
          },
          "code": {
            "type": "string",
            "description": "Maskinlesbar funnkode, f.eks. missing_attachment."
          },
          "message": {
            "type": "string"
          },
          "line_no": {
            "type": "integer",
            "description": "Valgfritt linjenummer i bilaget."
          },
          "field": {
            "type": "string",
            "description": "Valgfritt feltnavn funnet gjelder."
          }
        }
      },
      "VoucherReviewSummary": {
        "type": "object",
        "description": "Denormalisert kontrollstatus for et bilag. Følger med overalt hvor bilag hentes ut (liste, detalj, kø, hovedbok, fakturadetaljer). null-status betyr ukontrollert.",
        "properties": {
          "status": {
            "type": "string",
            "nullable": true,
            "enum": [
              null,
              "pending",
              "approved",
              "flagged",
              "rejected"
            ]
          },
          "reviewed_by_type": {
            "type": "string",
            "nullable": true,
            "enum": [
              null,
              "human",
              "ai"
            ]
          },
          "reviewed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "reviewed_by_user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "reviewed_by_name": {
            "type": "string",
            "nullable": true
          },
          "reviewed_by_email": {
            "type": "string",
            "nullable": true
          },
          "open_findings_count": {
            "type": "integer"
          },
          "is_human_reviewed": {
            "type": "boolean",
            "description": "true når status=approved og reviewed_by_type=human. Bruk denne for å vise «kontrollert av menneske»-symbol."
          }
        }
      },
      "VoucherReview": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "voucher_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "flagged",
              "rejected"
            ]
          },
          "reviewed_by_type": {
            "type": "string",
            "enum": [
              "human",
              "ai"
            ]
          },
          "reviewed_by_user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "ai_model": {
            "type": "string",
            "nullable": true
          },
          "note": {
            "type": "string",
            "nullable": true
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReviewFinding"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VoucherReviewInput": {
        "type": "object",
        "required": [
          "status",
          "reviewed_by_type"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "flagged",
              "rejected"
            ]
          },
          "reviewed_by_type": {
            "type": "string",
            "enum": [
              "human",
              "ai"
            ]
          },
          "ai_model": {
            "type": "string",
            "description": "Påkrevd når reviewed_by_type = ai."
          },
          "note": {
            "type": "string"
          },
          "findings": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/ReviewFinding"
            }
          }
        }
      },
      "BulkVoucherReviewInput": {
        "type": "object",
        "required": [
          "voucher_ids",
          "status",
          "reviewed_by_type"
        ],
        "properties": {
          "voucher_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "flagged",
              "rejected"
            ]
          },
          "reviewed_by_type": {
            "type": "string",
            "enum": [
              "human",
              "ai"
            ]
          },
          "ai_model": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "findings_by_voucher": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/ReviewFinding"
              }
            },
            "description": "Funn per bilag-id."
          }
        }
      },
      "BulkVoucherReviewResult": {
        "type": "object",
        "properties": {
          "created": {
            "type": "integer"
          },
          "failed": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "voucher_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "error": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "PaginatedVoucherReviews": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VoucherReview"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "ReviewCoverage": {
        "type": "object",
        "properties": {
          "period": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date",
                "nullable": true
              },
              "to": {
                "type": "string",
                "format": "date",
                "nullable": true
              }
            }
          },
          "total_vouchers": {
            "type": "integer"
          },
          "reviewed_human": {
            "type": "integer"
          },
          "reviewed_ai": {
            "type": "integer"
          },
          "unreviewed": {
            "type": "integer"
          },
          "flagged": {
            "type": "integer"
          },
          "open_findings": {
            "type": "integer"
          },
          "coverage_pct": {
            "type": "number",
            "description": "Andel kontrollerte bilag i prosent (0–100, 2 desimaler)."
          }
        }
      },
      "ReviewQueueItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Voucher"
          },
          {
            "type": "object",
            "properties": {
              "total_debit_nok": {
                "type": "string"
              },
              "line_count": {
                "type": "integer"
              },
              "lines": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                },
                "description": "Fulle posteringslinjer inkl. konto, MVA-kode og beløp."
              },
              "subledger": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "counterparties": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "name": {
                      "type": "string"
                    },
                    "org_number": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              },
              "attachments": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                },
                "description": "Vedleggsmetadata (filnavn, mime, størrelse, storage_path)."
              },
              "attachment_count": {
                "type": "integer"
              }
            }
          }
        ]
      },
      "PaginatedSupplierInvoices": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupplierInvoice"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "PaginatedOpenPosts": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenPost"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "InboxCount": {
        "type": "object",
        "required": [
          "count"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Antall innboks-bilag som matcher filtrene."
          }
        }
      },
      "PaginatedInbox": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InboxItem"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "LedgerLineInput": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/NokLine"
          },
          {
            "$ref": "#/components/schemas/CurrencyLine"
          }
        ],
        "description": "Bilagslinje. Enten NOK-variant (debit_nok/credit_nok) eller valuta-variant (amount/currency) — aldri begge. Serveren avviser blandinger med 400 invalid_ledger_line."
      },
      "BankTransaction": {
        "type": "object",
        "description": "En banktransaksjon hentet fra ZTL. Speilet av kontoutskrift hos banken. Status angir om transaksjonen er matchet mot en `payment_order`, ignorert, eller fortsatt åpen.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "ztl_bank_account_id": {
            "type": "string",
            "format": "uuid",
            "description": "FK til `ztl_bank_accounts.id`."
          },
          "ztl_account_id": {
            "type": "string",
            "description": "ZTLs eksterne konto-id."
          },
          "ztl_transaction_id": {
            "type": "string",
            "description": "ZTLs unike transaksjons-id (dedup-nøkkel)."
          },
          "ztl_payment_id": {
            "type": "string",
            "nullable": true,
            "description": "Hvis ZTL har koblet transaksjonen til en betaling vi initierte."
          },
          "booking_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "value_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3
          },
          "direction": {
            "type": "string",
            "enum": [
              "debit",
              "credit"
            ],
            "description": "`debit` = penger ut, `credit` = penger inn."
          },
          "counterparty_name": {
            "type": "string",
            "nullable": true
          },
          "counterparty_account": {
            "type": "string",
            "nullable": true,
            "description": "IBAN eller BBAN."
          },
          "remittance_info": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "unmatched",
              "matched",
              "ignored"
            ]
          },
          "matched_payment_order_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "matched_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "matched_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "match_method": {
            "type": "string",
            "nullable": true,
            "enum": [
              "ztl_payment_id",
              "amount_account_date",
              "manual"
            ],
            "description": "Hvordan matchen ble gjort. `ztl_payment_id` er sterkest (ZTL bekrefter), `amount_account_date` er heuristikk (beløp + motpartskonto + ±5 dager), `manual` er satt av bruker."
          },
          "note": {
            "type": "string",
            "nullable": true
          },
          "raw": {
            "type": "object",
            "additionalProperties": true,
            "description": "Rå JSON fra ZTL."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedBankTransactions": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankTransaction"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "BankTransactionSyncResult": {
        "type": "object",
        "required": [
          "ok",
          "fetched",
          "inserted",
          "skipped",
          "auto_matched"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "fetched": {
            "type": "integer",
            "description": "Antall transaksjoner hentet fra ZTL."
          },
          "inserted": {
            "type": "integer",
            "description": "Antall nye transaksjoner lagret lokalt."
          },
          "skipped": {
            "type": "integer",
            "description": "Allerede importert (dedup på `ztl_transaction_id`)."
          },
          "auto_matched": {
            "type": "integer",
            "description": "Antall som ble auto-matchet etter import."
          }
        }
      },
      "PartyBankAccount": {
        "type": "object",
        "description": "Bankkonto knyttet til en part (kunde/leverandør).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "party_id": {
            "type": "string",
            "format": "uuid"
          },
          "bank_account_number": {
            "type": "string",
            "nullable": true
          },
          "iban": {
            "type": "string",
            "nullable": true
          },
          "bic": {
            "type": "string",
            "nullable": true
          },
          "country_code": {
            "type": "string",
            "nullable": true
          },
          "label": {
            "type": "string",
            "nullable": true
          },
          "is_primary": {
            "type": "boolean"
          },
          "source": {
            "type": "string",
            "enum": [
              "manual",
              "ai",
              "edi"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ZtlBankAccount": {
        "type": "object",
        "description": "ZTL-bankkonto med koblet hovedboks-konto og betalingsmetode.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "ztl_account_id": {
            "type": "string"
          },
          "bban": {
            "type": "string",
            "nullable": true
          },
          "iban": {
            "type": "string",
            "nullable": true
          },
          "bic": {
            "type": "string",
            "nullable": true
          },
          "bank_name": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "ledger_account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "ledger_account": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "account_number": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "payment_method": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentMethod"
              }
            ]
          }
        }
      },
      "PaymentOrder": {
        "type": "object",
        "description": "Betalingsordre generert fra leverandørfaktura, klar for ZTL-signering.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "supplier_invoice_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "party_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "debtor_account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "creditor_name": {
            "type": "string",
            "nullable": true
          },
          "creditor_account_number": {
            "type": "string",
            "nullable": true
          },
          "creditor_iban": {
            "type": "string",
            "nullable": true
          },
          "creditor_bic": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "payment_type": {
            "type": "string",
            "enum": [
              "domestic",
              "cross_border"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "submitted",
              "awaiting_signing",
              "awaiting_cosigning",
              "signed",
              "executed",
              "failed",
              "rejected",
              "cancelled"
            ]
          },
          "requested_execution_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "remittance_message": {
            "type": "string",
            "nullable": true,
            "description": "Fri melding til betalingsmottaker (maks 140 tegn)."
          },
          "remittance_kid": {
            "type": "string",
            "nullable": true,
            "description": "KID-nummer for innbetaling (maks 25 tegn)."
          },
          "batch_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "ztl_payment_id": {
            "type": "string",
            "nullable": true
          },
          "ztl_status": {
            "type": "string",
            "nullable": true
          },
          "settlement_voucher_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaymentBatch": {
        "type": "object",
        "description": "Batch av betalingsordre sendt til ZTL for SCA-signering.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "awaiting_signing",
              "awaiting_cosigning",
              "signed",
              "executed",
              "failed",
              "cancelled"
            ]
          },
          "signing_id": {
            "type": "string",
            "nullable": true
          },
          "signing_url": {
            "type": "string",
            "nullable": true
          },
          "signing_qr": {
            "type": "string",
            "nullable": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BankReconciliation": {
        "type": "object",
        "description": "Bankavstemmingspost for ZTL-bankkonto og regnskapsperiode.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "ztl_bank_account_id": {
            "type": "string",
            "format": "uuid"
          },
          "period_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "approved",
              "reopened"
            ]
          },
          "closing_balance_bank": {
            "type": "number"
          },
          "closing_balance_ledger": {
            "type": "number",
            "nullable": true
          },
          "difference": {
            "type": "number",
            "nullable": true
          },
          "note": {
            "type": "string",
            "nullable": true
          },
          "approved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "approved_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BankReconciliationReport": {
        "type": "object",
        "description": "Fullstendig bankavstemmingsrapport med transaksjoner og differanseanalyse.",
        "properties": {
          "reconciliation": {
            "$ref": "#/components/schemas/BankReconciliation"
          },
          "matched_transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankTransaction"
            }
          },
          "unmatched_transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankTransaction"
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "total_matched": {
                "type": "number"
              },
              "total_unmatched": {
                "type": "number"
              },
              "difference": {
                "type": "number"
              }
            }
          }
        }
      },
      "VatReturn": {
        "type": "object",
        "description": "MVA-melding (mva_meldingen) for en termin sendt til Skatteetaten.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "year": {
            "type": "integer"
          },
          "term": {
            "type": "integer",
            "minimum": 1,
            "maximum": 6
          },
          "environment": {
            "type": "string",
            "enum": [
              "test",
              "prod"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "submitted",
              "accepted",
              "rejected",
              "failed"
            ]
          },
          "totals": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "mva_melding_xml": {
            "type": "string",
            "nullable": true
          },
          "altinn_instance_id": {
            "type": "string",
            "nullable": true
          },
          "submitted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "accepted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Product": {
        "type": "object",
        "description": "Produkt eller tjeneste brukt på salgsfakturering.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "sku": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "nullable": true
          },
          "unit_price": {
            "type": "number",
            "nullable": true
          },
          "currency": {
            "type": "string"
          },
          "vat_code": {
            "type": "string",
            "nullable": true
          },
          "income_account_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SalesInvoice": {
        "type": "object",
        "description": "Salgsfaktura/kundefaktura.",
        "properties": {
          "posted_voucher_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Bilaget fakturaen er bokført til (= `voucher_id`). Null så lenge fakturaen er kladd. 1:1 – ett bilag kan kun eies av én faktura.",
            "readOnly": true
          },
          "voucher": {
            "$ref": "#/components/schemas/VoucherRef"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "party_id": {
            "type": "string",
            "format": "uuid"
          },
          "invoice_number": {
            "type": "integer",
            "nullable": true
          },
          "invoice_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "kid": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string"
          },
          "fx_rate": {
            "type": "number"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "payment_method_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "sent",
              "posted",
              "paid",
              "cancelled"
            ]
          },
          "net_amount": {
            "type": "number",
            "nullable": true
          },
          "vat_amount": {
            "type": "number",
            "nullable": true
          },
          "total_amount": {
            "type": "number",
            "nullable": true
          },
          "voucher_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "sent_to": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "sent_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "delivery_status": {
            "type": "string",
            "enum": [
              "not_sent",
              "sent",
              "failed"
            ],
            "nullable": true
          },
          "last_send_error": {
            "type": "string",
            "nullable": true
          },
          "pdf_generated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "pdf_storage_path": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SalesInvoiceDelivery": {
        "type": "object",
        "description": "Logg-rad for ett utsendingsforsøk av en salgsfaktura.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "sales_invoice_id": {
            "type": "string",
            "format": "uuid"
          },
          "to_emails": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cc_emails": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bcc_emails": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "subject": {
            "type": "string",
            "nullable": true
          },
          "reply_to": {
            "type": "string",
            "nullable": true
          },
          "provider": {
            "type": "string",
            "example": "resend"
          },
          "provider_message_id": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "failed",
              "bounced",
              "complained"
            ]
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "sent_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "sent_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InboxEmailCheckResult": {
        "type": "object",
        "required": [
          "available",
          "domain"
        ],
        "description": "Resultat av sjekk om innboks-e-postadresse er ledig.",
        "properties": {
          "available": {
            "type": "boolean"
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "domain": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "NokLine": {
        "type": "object",
        "description": "NOK-variant: krever nøyaktig én av debit_nok/credit_nok. Feltene amount/currency/fx_rate er forbudt. Beløpet er BRUTTO når vat_code er satt (server splitter mva).",
        "required": [
          "account_number"
        ],
        "additionalProperties": false,
        "properties": {
          "account_number": {
            "type": "string",
            "description": "Kontonummer (unikt pr selskap), f.eks. \"3000\"."
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "vat_code": {
            "type": "string",
            "nullable": true,
            "description": "MVA-kode. Med rate > 0 tolkes beløpsfeltene som BRUTTO — server splitter mva ut på mva-kontoen i kontoplanen. Reskontro/bank-linjer skal ikke ha vat_code.",
            "example": "1"
          },
          "party_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Påkrevd når kontoen er reskontro (is_subledger=true)."
          },
          "invoice_number": {
            "type": "string",
            "nullable": true,
            "maxLength": 100
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "external_ref": {
            "type": "string",
            "nullable": true,
            "maxLength": 200
          },
          "debit_nok": {
            "type": "number",
            "minimum": 0,
            "description": "Brutto beløp inkl. mva når vat_code er satt."
          },
          "credit_nok": {
            "type": "number",
            "minimum": 0,
            "description": "Brutto beløp inkl. mva når vat_code er satt."
          }
        },
        "oneOf": [
          {
            "required": [
              "debit_nok"
            ],
            "not": {
              "required": [
                "credit_nok"
              ]
            }
          },
          {
            "required": [
              "credit_nok"
            ],
            "not": {
              "required": [
                "debit_nok"
              ]
            }
          }
        ]
      },
      "CurrencyLine": {
        "type": "object",
        "description": "Valuta-variant: krever amount + currency (ISO-4217). fx_rate/fx_rate_date valgfritt. Feltene debit_nok/credit_nok er forbudt. Beløpet er BRUTTO når vat_code er satt.",
        "required": [
          "account_number",
          "amount",
          "currency"
        ],
        "additionalProperties": false,
        "properties": {
          "account_number": {
            "type": "string",
            "description": "Kontonummer (unikt pr selskap), f.eks. \"3000\"."
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "vat_code": {
            "type": "string",
            "nullable": true,
            "description": "MVA-kode. Med rate > 0 tolkes beløpsfeltene som BRUTTO — server splitter mva ut på mva-kontoen i kontoplanen. Reskontro/bank-linjer skal ikke ha vat_code.",
            "example": "1"
          },
          "party_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Påkrevd når kontoen er reskontro (is_subledger=true)."
          },
          "invoice_number": {
            "type": "string",
            "nullable": true,
            "maxLength": 100
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "external_ref": {
            "type": "string",
            "nullable": true,
            "maxLength": 200
          },
          "amount": {
            "type": "number",
            "description": "Beløp i angitt valuta. Positivt = debet, negativt = kredit."
          },
          "currency": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "example": "EUR"
          },
          "fx_rate": {
            "type": "number",
            "description": "Valutakurs mot NOK. Utelatt = hentes fra fx_rates for fx_rate_date/voucher_date."
          },
          "fx_rate_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        }
      },
      "ReportPeriod": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string",
            "format": "date",
            "description": "Fra-dato (YYYY-MM-DD)"
          },
          "to": {
            "type": "string",
            "format": "date",
            "description": "Til-dato (YYYY-MM-DD)"
          }
        },
        "description": "Perioden rapporten dekker."
      },
      "TrialBalanceReport": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "debit_nok": {
                  "type": "string",
                  "description": "Sum debet i perioden."
                },
                "credit_nok": {
                  "type": "string"
                },
                "balance_nok": {
                  "type": "string",
                  "description": "Debet minus kredit."
                }
              }
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "total_debit": {
                "type": "string"
              },
              "total_credit": {
                "type": "string"
              },
              "balanced": {
                "type": "boolean",
                "description": "true når debet = kredit."
              }
            }
          }
        },
        "description": "Saldobalanse pr. konto."
      },
      "IncomeStatementReport": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "revenue": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "expenses": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "total_revenue": {
                "type": "string"
              },
              "total_expenses": {
                "type": "string"
              },
              "net_income": {
                "type": "string"
              }
            }
          }
        },
        "description": "Resultatregnskap pr. konto."
      },
      "ProfitLossReport": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "include_draft": {
            "type": "boolean",
            "description": "Om kladdebilag er tatt med."
          },
          "revenue": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "expenses": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "total_revenue": {
                "type": "string"
              },
              "total_expenses": {
                "type": "string"
              },
              "net_income": {
                "type": "string"
              }
            }
          },
          "monthly": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "month": {
                  "type": "string",
                  "description": "YYYY-MM"
                },
                "revenue": {
                  "type": "string"
                },
                "expenses": {
                  "type": "string"
                },
                "net_income": {
                  "type": "string"
                }
              }
            }
          }
        },
        "description": "Resultat med valgfri månedsfordeling (?monthly=true)."
      },
      "BalanceSheetReport": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "assets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "liabilities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "equity": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "total_assets": {
                "type": "string"
              },
              "total_liabilities": {
                "type": "string"
              },
              "total_equity": {
                "type": "string"
              },
              "balanced": {
                "type": "boolean"
              }
            }
          }
        },
        "description": "Balanse pr. dato."
      },
      "VatReport": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "year": {
            "type": "integer"
          },
          "term": {
            "type": "integer",
            "description": "MVA-termin (1–6)."
          },
          "include_draft": {
            "type": "boolean"
          },
          "accounts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "account_number": {
                  "type": "string"
                },
                "account_name": {
                  "type": "string"
                },
                "vat_code": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                }
              }
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "outgoing": {
                "type": "string",
                "description": "Utgående mva."
              },
              "incoming": {
                "type": "string",
                "description": "Inngående mva."
              },
              "net_payable": {
                "type": "string",
                "description": "Positiv = skyldig, negativ = tilgode."
              },
              "status": {
                "type": "string",
                "enum": [
                  "skyldig",
                  "tilgode"
                ]
              }
            }
          }
        },
        "description": "MVA-grunnlag pr. termin."
      },
      "LedgerReport": {
        "type": "object",
        "properties": {
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VoucherLine"
            }
          },
          "count": {
            "type": "integer"
          },
          "totals": {
            "type": "object",
            "properties": {
              "debit_nok": {
                "type": "string"
              },
              "credit_nok": {
                "type": "string"
              },
              "net_nok": {
                "type": "string"
              }
            }
          },
          "filters": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string"
              },
              "to": {
                "type": "string"
              },
              "account_number": {
                "type": "string"
              },
              "ledger_type": {
                "type": "string"
              },
              "party": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "description": "Hovedbok/reskontro-utlisting med totaler."
      },
      "AiContext": {
        "type": "object",
        "properties": {
          "purpose": {
            "type": "string"
          },
          "global_rules": {
            "type": "string",
            "description": "Systemets faste bokføringsregler."
          },
          "tenant_content": {
            "type": "string"
          },
          "company_content": {
            "type": "string"
          },
          "combined": {
            "type": "string",
            "description": "Sammenslått kontekst som sendes til AI."
          }
        }
      },
      "AiContextLearnResult": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "tenant",
              "company"
            ]
          },
          "previous_content": {
            "type": "string"
          },
          "proposed_content": {
            "type": "string"
          },
          "summary_of_change": {
            "type": "string"
          },
          "applied": {
            "type": "boolean",
            "description": "false ved dry_run."
          }
        }
      },
      "MatchResult": {
        "type": "object",
        "properties": {
          "close_group_id": {
            "type": "string",
            "format": "uuid"
          },
          "matched_count": {
            "type": "integer"
          },
          "party_id": {
            "type": "string",
            "format": "uuid"
          },
          "ledger_type": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "subledger_entry_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "applied_amount": {
                  "type": "string"
                },
                "open_amount": {
                  "type": "string"
                },
                "original_amount": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                }
              }
            }
          }
        },
        "description": "Resultat av en utligning."
      },
      "UnmatchResult": {
        "type": "object",
        "properties": {
          "unmatched_count": {
            "type": "integer"
          },
          "close_group_id": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "FxRateLookup": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string"
          },
          "requested_date": {
            "type": "string",
            "format": "date"
          },
          "actual_date": {
            "type": "string",
            "format": "date",
            "description": "Faktisk kursdato brukt (siste kjente ≤ requested_date)."
          },
          "rate": {
            "type": "number"
          },
          "source": {
            "type": "string"
          }
        }
      },
      "SalesInvoiceDetail": {
        "type": "object",
        "properties": {
          "posted_voucher_id": {
            "type": "string",
            "format": "uuid",
            "description": "Bilag fakturaen er bokført til, null før bokføring."
          },
          "voucher": {
            "$ref": "#/components/schemas/Voucher"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {}
            }
          }
        },
        "description": "Salgsfaktura med linjer og eventuelt bokført bilag. Inneholder i tillegg alle felter fra SalesInvoice."
      },
      "CompanyDeleteResult": {
        "type": "object",
        "properties": {
          "deleted": {
            "type": "boolean"
          },
          "company_id": {
            "type": "string",
            "format": "uuid"
          },
          "company_name": {
            "type": "string"
          },
          "storage_objects_removed": {
            "type": "integer"
          }
        }
      },
      "AuditLogPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditLog"
            }
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "ZtlConnectionResponse": {
        "type": "object",
        "properties": {
          "connection": {
            "type": "object",
            "properties": {}
          },
          "onboarding_url": {
            "type": "string"
          },
          "ztl_request_id": {
            "type": "string"
          }
        }
      },
      "ZtlConsentResponse": {
        "type": "object",
        "properties": {
          "consent_id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "valid_until": {
            "type": "string",
            "format": "date-time"
          },
          "sca": {
            "type": "object",
            "properties": {}
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/auth/signup": {
      "post": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Registrer ny bruker (kun med invitasjon)",
        "description": "**Offentlig selvregistrering er stengt (beta).** Konto kan kun opprettes med et gyldig `invitation_token` fra en invitasjonslenke. Tokenet valideres mot `tenant_invitations` (hash-oppslag, utløp, allerede brukt, e-postmatch) **før** brukeren opprettes; alle avvisninger gir `403`.\n\nVed gyldig token opprettes brukeren og en personlig tenant med brukeren som owner (ADR-016). Selve invitasjonen aksepteres etterpå via `POST /v1/invitations/{token}/accept` når brukeren er innlogget.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password",
                  "invitation_token"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "example": "you@example.com"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 6,
                    "example": "SuperSecret123"
                  },
                  "tenant_name": {
                    "type": "string",
                    "description": "Valgfritt navn på personlig tenant. Default: 'Personlig'."
                  },
                  "invitation_token": {
                    "type": "string",
                    "description": "**Påkrevd.** Klartekst-tokenet fra invitasjonslenken. Må være gyldig, ikke utløpt, ikke brukt, og invitasjonens e-post må matche `email` (case-insensitivt)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK — bruker og personlig tenant opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "email": {
                          "type": "string"
                        }
                      }
                    },
                    "session": {
                      "type": "object",
                      "properties": {
                        "access_token": {
                          "type": "string"
                        },
                        "refresh_token": {
                          "type": "string"
                        },
                        "expires_at": {
                          "type": "integer"
                        }
                      }
                    },
                    "tenant": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "name": {
                          "type": "string"
                        },
                        "kind": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Registrering avvist. `type` er én av: `signups_disabled` (mangler `invitation_token` — offentlig registrering er stengt), `invalid_invitation` (token finnes ikke, er ugyldig eller allerede brukt), `invitation_expired` (invitasjonen er utløpt), `invitation_email_mismatch` (invitasjonens e-post matcher ikke `email`). Brukeren blir ikke opprettet.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "signup"
      }
    },
    "/v1/auth/login": {
      "post": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Logg inn med e-post og passord",
        "description": "Returnerer `access_token`, `refresh_token`, `expires_in`, `user`. Bruk `access_token` som `Authorization: Bearer …` mot øvrige /v1/*.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "example": "you@example.com"
                  },
                  "password": {
                    "type": "string",
                    "example": "SuperSecret123"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "email": {
                          "type": "string"
                        }
                      }
                    },
                    "session": {
                      "type": "object",
                      "properties": {
                        "access_token": {
                          "type": "string"
                        },
                        "refresh_token": {
                          "type": "string"
                        },
                        "expires_at": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "login"
      }
    },
    "/v1/auth/refresh": {
      "post": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Forny access_token med refresh_token",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "refresh_token"
                ],
                "properties": {
                  "refresh_token": {
                    "type": "string",
                    "example": "..."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session": {
                      "type": "object",
                      "properties": {
                        "access_token": {
                          "type": "string"
                        },
                        "refresh_token": {
                          "type": "string"
                        },
                        "expires_at": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "refreshToken"
      }
    },
    "/v1/auth/logout": {
      "post": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Logg ut (invalider refresh-token)",
        "description": "Krever `Authorization: Bearer <access_token>`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Logget ut"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "logout"
      }
    },
    "/v1/auth/user": {
      "get": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Hent innlogget bruker",
        "description": "Returnerer brukeren (inkl. e-post) som tilhører `access_token`. Krever `Authorization: Bearer <access_token>`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "email": {
                          "type": "string"
                        },
                        "user_metadata": {
                          "type": "object",
                          "properties": {}
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getCurrentUser"
      }
    },
    "/v1/auth/forgot-password": {
      "post": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Send e-post for å tilbakestille passord",
        "description": "Starter passord-reset (ADR-020). API-et utsteder sitt **eget** engangstoken (aldri en Supabase/GoTrue-lenke) og sender e-posten via **Resend**. Lenken peker på `{redirect_base_url}/reset-password?token=...`, og passordet byttes med `POST /v1/auth/reset-password`. Klienten trenger dermed ingen Supabase-nøkkel.\n\nSvarer alltid `200`, også for ukjente e-postadresser (ingen bruker-enumerering). Maks 3 forespørsler per e-post per 15 minutter. Tokenet varer i 60 minutter og er engangsbruk.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "redirect_base_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Base-URL for lenken (`{base}/reset-password?token=...`). Må være vår egen base eller en origin registrert på en av brukerens tenants via `POST /v1/tenants/{tid}/app-origins`. Utelates feltet, brukes Lintels hostede side. Ukjent origin gir `400 invalid_redirect_base_url`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK — e-post sendt om brukeren finnes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "requestPasswordReset"
      }
    },
    "/v1/auth/reset-password": {
      "post": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Fullfør passord-reset med engangstoken",
        "description": "Bytter passordet med tokenet fra e-postlenken (ADR-020). Tokenet konsumeres atomisk og kan kun brukes én gang; alle andre åpne tokens for brukeren invalideres samtidig. Ved suksess returneres en ferdig sesjon slik at klienten slipper et ekstra login-kall — og aldri snakker med Supabase direkte.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "password"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "description": "Engangstokenet fra query-parameteren `token` i e-postlenken."
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "description": "Nytt passord, minst 8 tegn."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Passordet er oppdatert; sesjon returnert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "email": {
                          "type": "string",
                          "format": "email"
                        }
                      }
                    },
                    "access_token": {
                      "type": "string",
                      "nullable": true
                    },
                    "refresh_token": {
                      "type": "string",
                      "nullable": true
                    },
                    "expires_in": {
                      "type": "integer",
                      "nullable": true
                    },
                    "expires_at": {
                      "type": "integer",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_token` — ugyldig, brukt eller utløpt lenke",
            "$ref": "#/components/responses/Problem"
          },
          "422": {
            "description": "`weak_password` — passordet er for kort",
            "$ref": "#/components/responses/Problem"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "completePasswordReset"
      }
    },
    "/v1/auth/reset-password/{token}": {
      "get": {
        "tags": [
          "Autentisering"
        ],
        "summary": "Valider reset-token før skjemaet vises",
        "description": "Lar klientens egen reset-side sjekke om lenken fortsatt er gyldig, uten å konsumere tokenet. Ugyldig token gir `{ \"valid\": false }` uten ytterligere informasjon.",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tokenets status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "valid": {
                      "type": "boolean"
                    },
                    "email_masked": {
                      "type": "string",
                      "nullable": true,
                      "example": "so***@aicono.no"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "inspectPasswordResetToken"
      }
    },
    "/v1/tenants/{tid}/app-origins": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "List registrerte app-origins",
        "description": "Origins som er godkjent som `redirect_base_url` i invitasjons- og passord-reset-e-poster for denne tenanten (ADR-020).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "origins": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AppOrigin"
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listAppOrigins"
      },
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Registrer en app-origin (owner)",
        "description": "Selvbetjent registrering av klientappens domene, slik at e-postlenker kan peke dit. Kun `https` (unntatt `localhost`). Idempotent: samme origin to ganger gir samme rad.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "origin"
                ],
                "properties": {
                  "origin": {
                    "type": "string",
                    "format": "uri",
                    "example": "https://app.kunde.no"
                  },
                  "label": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registrert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppOrigin"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createAppOrigin"
      }
    },
    "/v1/tenants/{tid}/app-origins/{oid}": {
      "delete": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Fjern en app-origin (owner)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "oid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteAppOrigin"
      }
    },
    "/v1/me/memberships": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Berikte medlemskap (tenants + reachable companies)",
        "description": "ADR-014: returnerer alle tenants brukeren tilhører, med rolle og listen over selskaper vedkommende faktisk har tilgang til (eksplisitt `company_members`-rad, eller alle tenantens selskaper når tenant-rollen er `owner`). Samme sett som GET /v1/companies. Brukes til tenant-picker + selskaps-picker etter login.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembershipsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listMyMemberships"
      }
    },
    "/v1/finanstilsynet/search": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "searchFinanstilsynet",
        "summary": "Søk autoriserte regnskapsselskaper i Finanstilsynets register",
        "description": "Søker i Finanstilsynets åpne verksemdsregister filtrert på lisenstype `REGS` (Regnskapsselskap). Kun autoriserte regnskapsselskaper returneres, slik at et treff i seg selv dokumenterer autorisasjonen. Brukes i byrå-onboardingen (ADR-021). Feltene er normalisert til `TenantProfileInput` og beriket med `finanstilsynet_id`, `licence_types[]` og `licence_registered_at`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            },
            "description": "Selskapsnavn eller organisasjonsnummer."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FinanstilsynetSearchResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/Problem"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/public/finanstilsynet/search": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "searchFinanstilsynetPublic",
        "summary": "Offentlig søk i Finanstilsynets virksomhetsregister",
        "description": "Uautentisert variant av `GET /v1/finanstilsynet/search`, brukt i byrå-onboardingen på forsiden før innlogging. Returnerer kun offentlige registerdata fra Finanstilsynet (ingen data fra Lintel), filtrert på lisenstype `REGS`. Svaret caches i 60 sekunder og har CORS åpent.",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 120
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FinanstilsynetSearchResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "502": {
            "$ref": "#/components/responses/Problem"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/brreg/search": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "searchBrreg",
        "summary": "Søk selskap i Brønnøysundregistrenes enhetsregister",
        "description": "Brukes i onboarding når en innlogget bruker skal opprette en byråkonto (delt tenant). Søker på navn, eller på organisasjonsnummer når `q` er ni siffer. Treffene er normalisert til feltnavnene i `TenantProfileInput` slik at de kan sendes rett videre til `POST /v1/tenants`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2
            },
            "description": "Selskapsnavn eller organisasjonsnummer (9 siffer)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "results",
                    "total_count"
                  ],
                  "properties": {
                    "total_count": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "org_number": {
                            "type": "string",
                            "nullable": true
                          },
                          "name": {
                            "type": "string",
                            "nullable": true
                          },
                          "org_form": {
                            "type": "string",
                            "nullable": true
                          },
                          "address_line1": {
                            "type": "string",
                            "nullable": true
                          },
                          "address_line2": {
                            "type": "string",
                            "nullable": true
                          },
                          "postal_code": {
                            "type": "string",
                            "nullable": true
                          },
                          "city": {
                            "type": "string",
                            "nullable": true
                          },
                          "country_code": {
                            "type": "string",
                            "nullable": true
                          },
                          "website": {
                            "type": "string",
                            "nullable": true
                          },
                          "registered_at": {
                            "type": "string",
                            "format": "date",
                            "nullable": true
                          },
                          "bankrupt": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/public/brreg/search": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "searchBrregPublic",
        "summary": "Offentlig søk i Brønnøysundregistrenes enhetsregister",
        "description": "Uautentisert variant av `GET /v1/brreg/search`, brukt i byrå-onboardingen på forsiden slik at brukeren kan finne byrået sitt før innlogging. Returnerer kun offentlige registerdata (ingen data fra Lintel). Svaret caches i 60 sekunder og har CORS åpent.",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 120
            },
            "description": "Selskapsnavn eller organisasjonsnummer (9 siffer)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "results",
                    "total_count"
                  ],
                  "properties": {
                    "total_count": {
                      "type": "integer"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "org_number": {
                            "type": "string",
                            "nullable": true
                          },
                          "name": {
                            "type": "string",
                            "nullable": true
                          },
                          "org_form": {
                            "type": "string",
                            "nullable": true
                          },
                          "address_line1": {
                            "type": "string",
                            "nullable": true
                          },
                          "address_line2": {
                            "type": "string",
                            "nullable": true
                          },
                          "postal_code": {
                            "type": "string",
                            "nullable": true
                          },
                          "city": {
                            "type": "string",
                            "nullable": true
                          },
                          "country_code": {
                            "type": "string",
                            "nullable": true
                          },
                          "website": {
                            "type": "string",
                            "nullable": true
                          },
                          "registered_at": {
                            "type": "string",
                            "format": "date",
                            "nullable": true
                          },
                          "bankrupt": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants": {
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Opprett en delt tenant (regnskapsbyrå e.l.)",
        "description": "Oppretter en ny tenant med `kind='shared'`. Kaller blir første `owner`. **ADR-021:** tenanten opprettes med `status='pending'` og må godkjennes manuelt av oss før den kan brukes — kall mot en ikke-godkjent tenant gir `403 tenant_pending_approval`. Bruk dette når en bruker vil opprette et delt arbeidsområde — signup-flyten oppretter alltid kun en personlig tenant. Personlige tenants kan ikke opprettes via API.",
        "operationId": "createSharedTenant",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      }
                    }
                  },
                  {
                    "$ref": "#/components/schemas/TenantProfileInput"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants/{tid}": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "getTenant",
        "summary": "Hent tenantens profil (byråinformasjon)",
        "description": "Returnerer navn, logo, adresse og kontaktinformasjon for tenanten. Alle medlemmer av tenanten kan lese. Send `X-Tenant-Id` = `{tid}`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      },
      "patch": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "updateTenant",
        "summary": "Oppdater tenantens profil",
        "description": "Kun tenant-owner. Delvis oppdatering — kun feltene du sender endres. `null` nullstiller et felt. Endringen logges i revisjonssporet som `tenant.update`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      }
                    }
                  },
                  {
                    "$ref": "#/components/schemas/TenantProfileInput"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants/{tid}/companies": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tenant-selskaper"
        ],
        "operationId": "listTenantCompanies",
        "summary": "List selskaper koblet til tenanten",
        "description": "ADR-019: leser `tenant_companies` direkte og krever **ikke** at kalleren har `company_members`-tilgang. Bruk denne for å finne selskaper som ligger i tenanten uten aktive medlemmer. Kun owner/accountant. Send `X-Tenant-Id` = `{tid}`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "companies": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "name": {
                            "type": "string"
                          },
                          "org_number": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "relationship": {
                            "type": "string",
                            "enum": [
                              "owner",
                              "delegated"
                            ]
                          },
                          "added_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "member_count": {
                            "type": "integer",
                            "description": "Antall company_members i denne tenanten. 0 = selskapet er uten tilgang og må retildeles."
                          },
                          "owner_count": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants/{tid}/logo": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "uploadTenantLogo",
        "summary": "Last opp logo for tenanten",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "description": "Kun tenant-owner. Send enten `multipart/form-data` med feltet `file`, eller JSON med `file_base64`. Tillatte typer: PNG, JPEG, SVG, WebP. Maks 2 MB. Erstatter eventuell eksisterende logo og setter `tenants.logo_url` til den offentlige URL-en `/api/public/tenant-logos/{tid}` (ingen token kreves for å vise den).",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "file_base64"
                ],
                "properties": {
                  "file_base64": {
                    "type": "string",
                    "description": "Base64-kodet bilde, eventuelt som data-URL."
                  },
                  "file_name": {
                    "type": "string"
                  },
                  "mime_type": {
                    "type": "string",
                    "example": "image/png"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logoen er lastet opp",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tenant_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "logo_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "mime_type": {
                      "type": "string"
                    },
                    "file_size": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      },
      "delete": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "deleteTenantLogo",
        "summary": "Fjern logoen til tenanten",
        "description": "Kun tenant-owner. Sletter filen og nullstiller `logo_url`.",
        "responses": {
          "204": {
            "description": "Slettet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/public/tenant-logos/{tid}": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "operationId": "getTenantLogoPublic",
        "summary": "Hent tenantens logo (offentlig)",
        "description": "Serverer selve bildefilen uten autentisering, slik at logoen kan brukes i faktura-PDF-er, e-post og `<img>`-tagger. Caches i 5 minutter.",
        "security": [],
        "responses": {
          "200": {
            "description": "Bildefilen",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "Ingen logo satt for tenanten"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants/{tid}/companies/{cid}/members": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "cid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tenant-selskaper"
        ],
        "operationId": "listTenantCompanyMembers",
        "summary": "List selskapsmedlemmer (tenant-administrativt)",
        "description": "ADR-019: krever kun tenant-rolle owner/accountant + at selskapet er koblet til tenanten. Fungerer også når kalleren selv ikke har selskapstilgang.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "role": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      },
      "post": {
        "tags": [
          "Tenant-selskaper"
        ],
        "operationId": "assignTenantCompanyMember",
        "summary": "(Re)tildel selskapstilgang i tenanten",
        "description": "ADR-019: gjenopprettingsvei når et selskap står uten medlemmer. Kun **tenant-owner**. Upsert av `company_members` for (tenant, selskap, bruker) — brukeren må allerede være medlem av tenanten (`400 not_tenant_member` hvis ikke). Selskapet må være koblet til tenanten (`404`).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "user_id"
                ],
                "properties": {
                  "user_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "accountant",
                      "bookkeeper",
                      "viewer"
                    ],
                    "default": "owner"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Tilgang tildelt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "member": {
                      "type": "object",
                      "properties": {
                        "user_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "role": {
                          "type": "string"
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants/{tid}/companies/{cid}/members/{uid}": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "cid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "uid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "delete": {
        "tags": [
          "Tenant-selskaper"
        ],
        "operationId": "revokeTenantCompanyMember",
        "summary": "Fjern selskapstilgang (tenant-administrativt)",
        "description": "ADR-019: kun tenant-owner. Beskyttet av siste-eier-invarianten — forsøk på å fjerne den siste `owner` for (tenant, selskap) gir `409 last_owner`, uansett om tenanten eier selskapet eller har det delegert.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "Tilgang fjernet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/tenants/{tid}/invitations": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "List invitasjoner for tenanten",
        "description": "Kun owner/accountant i tenanten. Send `X-Tenant-Id` = `{tid}`. Default vises kun ikke-aksepterte invitasjoner (`status=pending`). Hver rad har `status` (`pending` | `accepted` | `expired`), `accepted_at` og `accepted_by`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filtrer på status. Default `pending`.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "accepted",
                "all"
              ],
              "default": "pending"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invitations": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "email": {
                            "type": "string"
                          },
                          "role": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "pending",
                              "accepted",
                              "expired"
                            ]
                          },
                          "expires_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "accepted_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "accepted_by": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true
                          },
                          "company_grants": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/CompanyGrant"
                            },
                            "description": "Selskapene brukeren får tilgang til ved accept. Tom liste = ingen selskapstilgang; tenant-rollen gir ikke implisitt tilgang til øvrige selskaper."
                          }
                        }
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TenantForbidden"
          },
          "409": {
            "$ref": "#/components/responses/AmbiguousTenant"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listTenantInvitations"
      },
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Opprett invitasjon til tenanten",
        "description": "Genererer et token (returneres kun én gang, som klartekst) og setter utløpsdato. Kun owner/accountant. Støtter valgfrie `company_grants` (pre-autoriserte per-selskap grants) og `transfer_ownership_company_id` (eierskifte fra denne tenanten til aksepterende tenant ved accept).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "role"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "accountant",
                      "bookkeeper",
                      "viewer"
                    ]
                  },
                  "permissions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "expires_in_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 14
                  },
                  "redirect_base_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Base-URL for invitasjonslenken ({base}/invitasjon/{token}). Må være whitelistet (env `INVITATION_REDIRECT_BASE_URLS` + innebygde), ellers `400 invalid_redirect_base_url`. Default er første whitelistede verdi."
                  },
                  "company_grants": {
                    "type": "array",
                    "description": "ADR-014: pre-autoriserte per-selskap grants som materialiseres ved accept.",
                    "items": {
                      "$ref": "#/components/schemas/CompanyGrant"
                    }
                  },
                  "transfer_ownership_company_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "ADR-014: hvis satt, flyttes eierskap for selskapet fra inviterende tenant til aksepterende tenant ved accept. Krever at inviterende tenant har `relationship='delegated'` — eiere kan ikke gi bort seg selv via invitasjon."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invitasjon opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "email": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "token": {
                      "type": "string",
                      "description": "Klartekst-token — vises kun ved opprettelse."
                    },
                    "invitation_url": {
                      "type": "string",
                      "description": "Full lenke sendt til invitert ({base}/invitasjon/{token})."
                    },
                    "email_sent": {
                      "type": "boolean",
                      "description": "Om invitasjonsmailen ble sendt."
                    },
                    "email_error": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TenantForbidden"
          },
          "409": {
            "$ref": "#/components/responses/AmbiguousTenant"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createTenantInvitation"
      }
    },
    "/v1/tenants/{tid}/invitations/{iid}": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "iid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "delete": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Kansellér en invitasjon",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Kansellert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "cancelTenantInvitation"
      }
    },
    "/v1/invitations/{token}": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Hent invitasjonsdetaljer (offentlig)",
        "description": "Ingen auth påkrevd. Returnerer tenant-navn, e-post, rolle og utløpsdato. Brukes til å vise 'Godta invitasjon'-side før signup/innlogging.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tenant_name": {
                      "type": "string"
                    },
                    "email": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getInvitation"
      }
    },
    "/v1/invitations/{token}/accept": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Godta en invitasjon som innlogget bruker",
        "description": "Autentisert bruker aksepterer invitasjonen og får en `members`-rad i den inviterende tenanten. E-post på JWT må matche invitasjonens e-post.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Akseptert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "tenant_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "role": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "acceptInvitation",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/v1/tenants/{tid}/invitations/{iid}/resend": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "iid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Send invitasjonen på nytt",
        "description": "Roterer tokenet, forlenger utløpet og sender invitasjonsmailen på nytt. Kun owner/accountant i tenanten. Allerede akseptert invitasjon gir `409 invitation_already_accepted`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "redirect_base_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Base-URL for lenken ({base}/invitasjon/{token}). Må være whitelistet, ellers `400 invalid_redirect_base_url`."
                  },
                  "expires_in_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 14
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sendt på nytt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "email": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "token": {
                      "type": "string",
                      "description": "Nytt klartekst-token."
                    },
                    "invitation_url": {
                      "type": "string"
                    },
                    "email_sent": {
                      "type": "boolean"
                    },
                    "email_error": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TenantForbidden"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "resendTenantInvitation"
      }
    },
    "/v1/me/invitations": {
      "get": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Mine åpne invitasjoner",
        "description": "Lister alle pending, ikke-utløpte invitasjoner som matcher e-posten på JWT-en. Krever ikke `X-Tenant-Id` og fungerer for brukere uten tenant-medlemskap. `accept_id` brukes mot `POST /v1/me/invitations/{id}/accept`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invitations": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "accept_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "tenant_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "tenant_name": {
                            "type": "string"
                          },
                          "role": {
                            "type": "string"
                          },
                          "permissions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "expires_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listMyInvitations"
      }
    },
    "/v1/me/invitations/{id}/accept": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Tenants og invitasjoner"
        ],
        "summary": "Godta invitasjon uten klartekst-token",
        "description": "Godtar invitasjonen basert på id fra `GET /v1/me/invitations`. Verifiseres på e-postmatch mot JWT-en. `409 invitation_already_accepted` / `410 invitation_expired` skiller tilstandene.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Akseptert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tenant_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "role": {
                      "type": "string"
                    },
                    "company_grants_applied": {
                      "type": "integer"
                    },
                    "ownership_transfer_applied": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "acceptMyInvitation"
      }
    },
    "/v1/companies": {
      "get": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Liste selskaper i din tenant",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedCompanies"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listCompanies"
      },
      "post": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Opprett nytt selskap",
        "description": "Oppretter selskap, regnskapsår og 12 månedsperioder.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "example": "Acme Norge AS"
                  },
                  "org_number": {
                    "type": "string",
                    "nullable": true,
                    "example": "999888777"
                  },
                  "functional_currency": {
                    "type": "string",
                    "default": "NOK"
                  },
                  "fiscal_year": {
                    "type": "object",
                    "properties": {
                      "year": {
                        "type": "integer",
                        "example": 2026
                      },
                      "start_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                      },
                      "end_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "company": {
                      "$ref": "#/components/schemas/Company"
                    },
                    "fiscal_year": {
                      "$ref": "#/components/schemas/FiscalYear"
                    },
                    "periods_created": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createCompany"
      }
    },
    "/v1/companies/{id}": {
      "get": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Hent selskap",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getCompany"
      },
      "patch": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Oppdater selskap",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "org_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "functional_currency": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateCompany"
      },
      "delete": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Slett selskap permanent (irreversibelt)",
        "description": "Sletter selskapet og ALL tilhørende data i én transaksjon: bilag og posteringer, vedlegg, leverandør- og salgsfakturaer, bilagsmottak, parter, produkter, kontoplan, perioder og regnskapsår, mva-meldinger, betalinger og betalingsbunter, bankforbindelser og banktransaksjoner, avstemminger, selskapsmedlemskap, tenant-kobling, revisjonslogg og forespørselslogg. Filer i lagring (bilagsvedlegg og bilagsmottak) fjernes også.\n\nKrav: kaller må ha rollen `owner` i aktiv tenant, og aktiv tenant må være **eier** av selskapet (`tenant_companies.relationship = 'owner'`) — delegerte tenants får 403. Bekreftelse kreves via query-parameteret `confirm`, som må matche selskapsnavnet eksakt.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "confirm",
            "in": "query",
            "required": true,
            "description": "Må være eksakt lik selskapets navn.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Selskapet er slettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted",
                    "company_id"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "example": true
                    },
                    "company_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "company_name": {
                      "type": "string",
                      "nullable": true
                    },
                    "storage_objects_removed": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "confirmation_required — `confirm` mangler eller matcher ikke selskapsnavnet",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteCompany"
      }
    },
    "/v1/companies/{id}/members": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Selskapsmedlemmer"
        ],
        "summary": "Liste medlemmer i selskapet",
        "description": "Returnerer kun brukere med eksplisitt selskapstilgang (`company_members`). Tenant-rollen gir ingen implisitt tilgang til selskapene i tenanten. Sett `include_tenant_members=true` for å også få tenant-medlemmer uten selskapstilgang (`has_company_access=false`).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "name": "include_tenant_members",
            "in": "query",
            "required": false,
            "description": "Ta med tenant-medlemmer uten selskapstilgang.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "members"
                  ],
                  "properties": {
                    "members": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CompanyMember"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TenantForbidden"
          },
          "409": {
            "$ref": "#/components/responses/AmbiguousTenant"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listCompanyMembers"
      },
      "post": {
        "tags": [
          "Selskapsmedlemmer"
        ],
        "summary": "Gi bruker tilgang til selskapet",
        "description": "Kun owner/accountant i tenanten. Setter per-selskap `role`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "user_id",
                  "role"
                ],
                "properties": {
                  "user_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "accountant",
                      "bookkeeper",
                      "viewer"
                    ],
                    "default": "bookkeeper"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyMember"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "addCompanyMember"
      }
    },
    "/v1/companies/{id}/members/{uid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "uid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "patch": {
        "tags": [
          "Selskapsmedlemmer"
        ],
        "summary": "Oppdater rolle / tilganger eller trekk selskapstilgang",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "accountant",
                      "bookkeeper",
                      "viewer"
                    ]
                  },
                  "permissions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "revoke_company_access": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateCompanyMember"
      },
      "delete": {
        "tags": [
          "Selskapsmedlemmer"
        ],
        "summary": "Fjern per-selskap tilgang",
        "description": "Sletter `company_members`-raden. Blokkeres med `409 last_owner` hvis dette er den siste `owner`-brukeren for selskapet i eier-tenanten. Håndheves også av en DB-trigger.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/LastOwner"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "removeCompanyMember"
      }
    },
    "/v1/companies/{id}/accounts": {
      "get": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Liste konti",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "is_active",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "account_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asset",
                "liability",
                "equity",
                "income",
                "expense"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedAccounts"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listAccounts"
      },
      "post": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Opprett konto",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "account_number",
                  "name",
                  "account_type"
                ],
                "properties": {
                  "account_number": {
                    "type": "string",
                    "example": "1500"
                  },
                  "name": {
                    "type": "string",
                    "example": "Kundefordringer"
                  },
                  "account_type": {
                    "type": "string",
                    "enum": [
                      "asset",
                      "liability",
                      "equity",
                      "income",
                      "expense",
                      "revenue"
                    ],
                    "description": "Kanoniske verdier: asset, liability, equity, income, expense. Aliaset 'revenue' godtas og normaliseres til 'income' (tilsvarende 'cost' → 'expense')."
                  },
                  "naerings_spec_code": {
                    "type": "string",
                    "example": "1500",
                    "description": "Valgfri. Utledes fra kontonummer og kontotype når den utelates (f.eks. 3602 → 3000)."
                  },
                  "vat_code": {
                    "type": "string",
                    "nullable": true
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  },
                  "is_subledger": {
                    "type": "boolean",
                    "default": false,
                    "description": "Reskontrokonto (krever party_id på posteringer)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createAccount"
      }
    },
    "/v1/naerings-spec-codes": {
      "get": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Næringsspesifikasjonskoder (oppslag)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "codes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listNaeringsSpecCodes"
      }
    },
    "/v1/companies/{id}/vat-codes": {
      "get": {
        "tags": [
          "Grunndata"
        ],
        "summary": "MVA-koder (selskaps-eide)",
        "description": "ADR-019: alle MVA-koder er selskaps-eide rader med uuid-`id`. Nye selskaper seedes fra standardmalen. `code` er en mutbar etikett innenfor selskapet; `id` er den autoritative referansen som lagres på posteringer og fakturalinjer.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "is_active",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "vat_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "outgoing",
                "incoming",
                "none",
                "reverse_charge",
                "exempt"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vat_codes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VatCode"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listVatCodes"
      },
      "post": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Opprett MVA-kode",
        "description": "Oppretter en MVA-kode for selskapet. Krever `vat_code.manage`. `code` er en fri etikett (unik pr. selskap) — ingen prefikskrav. Bruk `deduction_rate` (0–100) for forholdsmessig fradrag på `incoming` / `reverse_charge`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code",
                  "name",
                  "rate",
                  "vat_type"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "example": "1-60",
                    "description": "Fri etikett, unik innenfor selskapet."
                  },
                  "name": {
                    "type": "string",
                    "example": "Inng. MVA 25% – 60% fradrag (delt virksomhet)"
                  },
                  "rate": {
                    "type": "number",
                    "example": 25
                  },
                  "vat_type": {
                    "type": "string",
                    "enum": [
                      "incoming",
                      "outgoing",
                      "reverse_charge",
                      "none",
                      "exempt"
                    ]
                  },
                  "vat_account_number": {
                    "type": "string",
                    "nullable": true,
                    "example": "2710"
                  },
                  "reverse_charge_account_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "deduction_rate": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 100,
                    "description": "Andel av inngående MVA som er fradragsberettiget. < 100 kun gyldig for incoming/reverse_charge."
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  },
                  "sort_order": {
                    "type": "integer",
                    "default": 100
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vat_code": {
                      "$ref": "#/components/schemas/VatCode"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ugyldig body (bl.a. invalid_deduction_rate, missing_vat_account)"
          },
          "403": {
            "description": "Mangler vat_code.manage"
          },
          "409": {
            "description": "code_in_use – kodestrengen finnes allerede for selskapet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createVatCode"
      }
    },
    "/v1/companies/{id}/vat-codes/{code}": {
      "patch": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Oppdater MVA-kode",
        "description": "Oppdaterer en MVA-kode. Path-parameteret aksepterer både `vat_codes.id` (uuid) og kodestrengen. `code` og `name` kan alltid endres (etikett). `rate`, `deduction_rate` og `vat_type` er frosset så snart koden er brukt i bokførte bilag (409 `locked_usage`) — opprett heller en ny kode.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "`vat_codes.id` (uuid) eller kodestrengen.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "Ny etikett. Kan endres når som helst."
                  },
                  "vat_type": {
                    "type": "string",
                    "enum": [
                      "incoming",
                      "outgoing",
                      "reverse_charge",
                      "none",
                      "exempt"
                    ]
                  },
                  "name": {
                    "type": "string"
                  },
                  "rate": {
                    "type": "number"
                  },
                  "vat_account_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "reverse_charge_account_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "deduction_rate": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "is_active": {
                    "type": "boolean"
                  },
                  "sort_order": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vat_code": {
                      "$ref": "#/components/schemas/VatCode"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler vat_code.manage"
          },
          "404": {
            "description": "not_found"
          },
          "409": {
            "description": "locked_usage – sats/fradrag/type er frosset fordi koden er brukt i bokførte bilag. code_in_use – kodestrengen er allerede i bruk."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateVatCode"
      },
      "delete": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Slett MVA-kode",
        "description": "Sletter en MVA-kode som ikke er brukt. Path-parameteret aksepterer både uuid og kodestreng. Hvis koden er brukt på posteringer returneres 409 `in_use` — deaktiver i stedet via PATCH `is_active=false`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "`vat_codes.id` (uuid) eller kodestrengen.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "403": {
            "description": "Mangler vat_code.manage"
          },
          "404": {
            "description": "not_found"
          },
          "409": {
            "description": "in_use – koden er brukt på posteringer"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteVatCode"
      }
    },
    "/v1/companies/{id}/periods": {
      "get": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Liste perioder",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra-dato (YYYY-MM-DD). Inkluderer perioder som overlapper.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til-dato (YYYY-MM-DD). Inkluderer perioder som overlapper.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-12-31"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "closed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "periods": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Period"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listPeriods"
      }
    },
    "/v1/companies/{id}/periods/{pid}/close": {
      "post": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Lukk periode (kaskaderer bakover)",
        "description": "Lukker perioden mykt (`level: 'soft'`, default) eller hardt (`level: 'hard'`, kun owner). **Kronologisk konsistens:** alle tidligere perioder i selskapet som er mindre låst enn målnivået lukkes i samme operasjon. MVA-låste perioder hoppes over (de er allerede låst). Kaskaderte perioder returneres i `cascaded_closed`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "level": {
                    "type": "string",
                    "enum": [
                      "soft",
                      "hard"
                    ],
                    "default": "soft"
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lukket",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Period"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "draft_vouchers_count": {
                          "type": "integer"
                        },
                        "warning": {
                          "type": "string",
                          "nullable": true
                        },
                        "cascaded_closed": {
                          "type": "array",
                          "description": "Tidligere perioder som ble lukket i samme operasjon.",
                          "items": {
                            "$ref": "#/components/schemas/PeriodBrief"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "closePeriod"
      }
    },
    "/v1/companies/{id}/periods/{pid}/reopen": {
      "post": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Gjenåpne periode (kaskaderer fremover)",
        "description": "Gjenåpner perioden (`status` og `lock_level` settes til `open`). **Kronologisk konsistens:** alle senere perioder i selskapet som ikke er helt åpne gjenåpnes i samme operasjon. MVA-låste perioder hoppes over (`skipped_vat_locked`), og hardt lukkede perioder hoppes over for ikke-owners (`skipped_hard_closed`). Hard reopen av selve målperioden krever owner-rolle og `reason`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Påkrevd ved hard reopen."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Gjenåpnet",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Period"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "cascaded_reopened": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/PeriodBrief"
                          }
                        },
                        "skipped_vat_locked": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/PeriodBrief"
                          }
                        },
                        "skipped_hard_closed": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/PeriodBrief"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "reopenPeriod"
      }
    },
    "/v1/companies/{id}/vouchers/review-queue": {
      "get": {
        "tags": [
          "Bilagskontroll"
        ],
        "operationId": "getVoucherReviewQueue",
        "summary": "Kø av ukontrollerte bilag (fullt beriket for AI-analyse)",
        "description": "Returnerer de neste N ukontrollerte bilagene med fulle posteringslinjer, MVA-koder, motparter og vedleggsmetadata, slik at en AI kan analysere flere bilag i ett kall.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 200
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "oldest = eldste først, largest = største beløp først, risk = heuristisk risikoscore.",
            "schema": {
              "type": "string",
              "enum": [
                "oldest",
                "largest",
                "risk"
              ],
              "default": "oldest"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ReviewQueueItem"
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "order": {
                      "type": "string"
                    },
                    "candidate_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/reviews": {
      "get": {
        "tags": [
          "Bilagskontroll"
        ],
        "operationId": "listVoucherReviews",
        "summary": "Historikk for kvalitetskontroll av ett bilag (nyeste først)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "description": "Bilag-ID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedVoucherReviews"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      },
      "post": {
        "tags": [
          "Bilagskontroll"
        ],
        "operationId": "createVoucherReview",
        "summary": "Registrer kvalitetskontroll på et bilag",
        "description": "Krever `voucher.create`. Kan settes på både draft og posted bilag, og blokkerer ikke postering. Loggføres i revisjonsloggen som `voucher.review.created`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "description": "Bilag-ID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoucherReviewInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "review": {
                      "$ref": "#/components/schemas/VoucherReview"
                    },
                    "voucher": {
                      "type": "object",
                      "description": "Oppdaterte review-felter på bilaget.",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/reviews/{rid}": {
      "delete": {
        "tags": [
          "Bilagskontroll"
        ],
        "operationId": "deleteVoucherReview",
        "summary": "Angre en kvalitetskontroll",
        "description": "Kun egen review, eller rollen owner/accountant. Gjeldende status faller tilbake til forrige review (eller `unreviewed`). Loggføres som `voucher.review.deleted`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "description": "Bilag-ID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "rid",
            "in": "path",
            "required": true,
            "description": "Review-ID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "review_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "voucher": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/companies/{id}/voucher-reviews/bulk": {
      "post": {
        "tags": [
          "Bilagskontroll"
        ],
        "operationId": "bulkCreateVoucherReviews",
        "summary": "Registrer kvalitetskontroll på mange bilag (maks 500)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkVoucherReviewInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkVoucherReviewResult"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/companies/{id}/reports/review-coverage": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "operationId": "getReviewCoverage",
        "summary": "Kontrolldekning for bilag i en periode",
        "description": "Aggregert oversikt over hvor stor andel av bilagene som er kvalitetskontrollert. Bygger på denormaliserte felter på bilaget og er derfor rask nok til å kalles for mange selskaper.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReviewCoverage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/v1/companies/{id}/vouchers": {
      "get": {
        "tags": [
          "Bilag"
        ],
        "summary": "Liste bilag",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "posted",
                "reversed"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "manual",
                "supplier_invoice",
                "payment",
                "reversal"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra bilagsdato (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til bilagsdato (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "review_status",
            "in": "query",
            "description": "Filtrer på kontrollstatus. Kommaseparert liste. `unreviewed` = bilag uten review.",
            "schema": {
              "type": "string",
              "example": "unreviewed,flagged"
            }
          },
          {
            "name": "reviewed_by_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "human",
                "ai"
              ]
            }
          },
          {
            "name": "has_findings",
            "in": "query",
            "description": "true = kun bilag med åpne funn (warning/error).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedVouchers"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listVouchers"
      },
      "post": {
        "tags": [
          "Bilag"
        ],
        "summary": "Opprett manuelt bilag (kan postere direkte med post:true)",
        "description": "Oppretter et manuelt bilag (`source='manual'`). Hvis `post: true` settes, valideres balanse og bilaget bokføres umiddelbart (tildeler `voucher_no`, krever `voucher.post`-rettighet). Ellers opprettes som draft.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "voucher_date",
                  "description"
                ],
                "properties": {
                  "voucher_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Bilagsdato. Periode bestemmes automatisk."
                  },
                  "description": {
                    "type": "string",
                    "example": "Manuell postering"
                  },
                  "post": {
                    "type": "boolean",
                    "default": false,
                    "description": "Hvis true, bokfør umiddelbart."
                  },
                  "lines": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/LedgerLineInput"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet (draft eller posted)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voucher"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createVoucher"
      }
    },
    "/v1/companies/{id}/vouchers/{vid}": {
      "get": {
        "tags": [
          "Bilag"
        ],
        "summary": "Hent bilag (med linjer, betalinger og vedlegg)",
        "description": "Returnerer bilaget med posteringslinjer, eventuelle betalingsbilag som peker på dette bilaget, og vedlegg. Hvert vedlegg inkluderer en signert `download_url` som er gyldig i 1 time.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "voucher": {
                      "$ref": "#/components/schemas/Voucher"
                    },
                    "source": {
                      "type": "string",
                      "nullable": true,
                      "description": "Hvor bilaget kom fra, f.eks. `supplier_invoice`, `sales_invoice`, `manual`."
                    },
                    "source_document": {
                      "type": "object",
                      "nullable": true,
                      "description": "Kildedokumentet som eier bilaget (1:1). `null` for manuelle bilag.",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "supplier_invoice",
                            "sales_invoice"
                          ]
                        },
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        }
                      }
                    },
                    "lines": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "payments": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "attachments": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "file_name": {
                            "type": "string"
                          },
                          "mime_type": {
                            "type": "string"
                          },
                          "file_size": {
                            "type": "integer"
                          },
                          "storage_path": {
                            "type": "string"
                          },
                          "download_url": {
                            "type": "string",
                            "nullable": true
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getVoucher"
      },
      "patch": {
        "tags": [
          "Bilag"
        ],
        "summary": "Oppdater bilag-header (draft, eller posted hvis perioden er åpen)",
        "description": "Oppdater `voucher_date` og/eller `description`. Tillatt for `draft` og `posted` så lenge perioden er åpen. Endrer `voucher_date` periode, oppdateres `period_id` automatisk.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "voucher_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voucher"
                }
              }
            }
          },
          "422": {
            "description": "Periode lukket eller ugyldig status"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateVoucher"
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/lines": {
      "put": {
        "tags": [
          "Bilag"
        ],
        "summary": "Erstatt posteringslinjer (draft, eller posted hvis perioden er åpen)",
        "description": "Erstatter alle posteringslinjer på bilaget. Validerer balanse og MVA. Tillatt for `draft` og `posted` så lenge perioden er åpen. Bruk når AI har bommet på bokføringen og brukeren vil korrigere.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "lines"
                ],
                "properties": {
                  "lines": {
                    "type": "array",
                    "minItems": 2,
                    "items": {
                      "$ref": "#/components/schemas/LedgerLineInput"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Linjer oppdatert. Returnerer berikede linjer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lines": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VoucherLine"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Ubalansert, lukket periode, eller ugyldig status."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "replaceVoucherLines"
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/post": {
      "post": {
        "tags": [
          "Bilag"
        ],
        "summary": "Bokfør bilag (tildeler bilagsnr, sjekker balanse)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Bokført",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voucher"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "postVoucher"
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/reverse": {
      "post": {
        "tags": [
          "Bilag"
        ],
        "summary": "Reverser bokført bilag",
        "description": "Oppretter og bokfører et motbilag med speilvendte linjer. MVA-metadata (`vat_code`, `vat_code_id`, `vat_amount`, `vat_basis`, `gross_amount`) kopieres med motsatt fortegn, slik at reverseringen inngår i MVA-meldingen.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Reversert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "voucher": {
                      "$ref": "#/components/schemas/Voucher"
                    },
                    "reverses": {
                      "type": "string",
                      "format": "uuid",
                      "description": "ID på opprinnelig bilag."
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "reverseVoucher"
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/attachments": {
      "post": {
        "tags": [
          "Bilag"
        ],
        "summary": "Last opp vedlegg (multipart) eller registrer metadata",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "file_name",
                  "mime_type",
                  "file_size",
                  "storage_path"
                ],
                "properties": {
                  "file_name": {
                    "type": "string"
                  },
                  "mime_type": {
                    "type": "string"
                  },
                  "file_size": {
                    "type": "integer"
                  },
                  "storage_path": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "file_name": {
                      "type": "string"
                    },
                    "storage_path": {
                      "type": "string"
                    },
                    "mime_type": {
                      "type": "string"
                    },
                    "size_bytes": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "uploadVoucherAttachment"
      }
    },
    "/v1/companies/{id}/inbox": {
      "get": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "List opplastede bilag (AI-tolkede)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedInbox"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listInboxItems"
      },
      "post": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Last opp et bilag (PDF/bilde) — AI tolker og oppretter leverandørfaktura-utkast",
        "description": "Synkron flyt:\n\n1. Filen lastes opp til `inbox` storage-bucketen.\n2. AI tolker hele dokumentet (header + linjer) og foreslår konto/MVA-koder per linje.\n3. Et utkast til **leverandørfaktura** (`supplier_invoices` med `status='draft'`) opprettes automatisk og lenkes til inbox-elementet via `supplier_invoice_id`.\n\nFrontend kan deretter åpne leverandørfakturaen for redigering og attestering via `/v1/companies/{id}/supplier-invoices/{siid}`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Bilaget er lastet opp, AI har tolket dataen og en draft leverandørfaktura er opprettet. `supplier_invoice_id` peker på utkastet som kan attesteres via /supplier-invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "inbox_item_id (brukes ved bokføring)"
                    },
                    "file_name": {
                      "type": "string"
                    },
                    "mime_type": {
                      "type": "string"
                    },
                    "storage_path": {
                      "type": "string",
                      "description": "Path i `inbox` storage-bucketen."
                    },
                    "party_id": {
                      "type": "string",
                      "format": "uuid",
                      "nullable": true
                    },
                    "party": {
                      "type": "object",
                      "nullable": true,
                      "description": "Leverandør (auto-opprettet eller matchet på org.nr/navn).",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "name": {
                          "type": "string"
                        },
                        "org_number": {
                          "type": "string",
                          "nullable": true
                        },
                        "is_supplier": {
                          "type": "boolean"
                        },
                        "is_customer": {
                          "type": "boolean"
                        },
                        "ap_account_id": {
                          "type": "string",
                          "format": "uuid",
                          "nullable": true
                        }
                      }
                    },
                    "extracted": {
                      "type": "object",
                      "description": "AI-tolket fakturadata, beriket med konto- og MVA-objekter.",
                      "properties": {
                        "supplier_name": {
                          "type": "string"
                        },
                        "supplier_org_number": {
                          "type": "string"
                        },
                        "invoice_number": {
                          "type": "string"
                        },
                        "invoice_date": {
                          "type": "string",
                          "format": "date"
                        },
                        "due_date": {
                          "type": "string",
                          "format": "date"
                        },
                        "kid": {
                          "type": "string"
                        },
                        "currency": {
                          "type": "string",
                          "description": "ISO 4217, f.eks. NOK"
                        },
                        "net_amount": {
                          "type": "number"
                        },
                        "vat_amount": {
                          "type": "number"
                        },
                        "total_amount": {
                          "type": "number"
                        },
                        "description": {
                          "type": "string"
                        },
                        "suggested_account_number": {
                          "type": "string",
                          "description": "AI-foreslått kontonummer for hele bilaget."
                        },
                        "suggested_vat_code": {
                          "type": "string",
                          "description": "AI-foreslått MVA-kode for hele bilaget."
                        },
                        "account": {
                          "type": "object",
                          "nullable": true,
                          "description": "Oppslått konto-objekt for `suggested_account_number`.",
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid"
                            },
                            "account_number": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "account_type": {
                              "type": "string"
                            }
                          }
                        },
                        "vat_code": {
                          "type": "object",
                          "nullable": true,
                          "description": "Oppslått MVA-kode-objekt for `suggested_vat_code`.",
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "rate": {
                              "type": "number"
                            },
                            "vat_type": {
                              "type": "string"
                            }
                          }
                        },
                        "lines": {
                          "type": "array",
                          "description": "Fakturalinjer. Hver linje har AI-forslag (suggested_*) PLUS fulle `account`- og `vat_code`-objekter for direkte bruk i frontend.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "description": {
                                "type": "string"
                              },
                              "quantity": {
                                "type": "number"
                              },
                              "unit_price": {
                                "type": "number"
                              },
                              "vat_rate": {
                                "type": "number",
                                "description": "MVA-sats i % (f.eks. 25)."
                              },
                              "amount": {
                                "type": "number",
                                "description": "Beløp inkl. MVA (gross)."
                              },
                              "suggested_account_number": {
                                "type": "string"
                              },
                              "suggested_vat_code": {
                                "type": "string"
                              },
                              "account": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "format": "uuid"
                                  },
                                  "account_number": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "account_type": {
                                    "type": "string"
                                  }
                                }
                              },
                              "vat_code": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "rate": {
                                    "type": "number"
                                  },
                                  "vat_type": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Mangler fil eller feil content-type (krever multipart/form-data)."
          },
          "402": {
            "description": "AI-kreditt oppbrukt."
          },
          "429": {
            "description": "AI rate limit."
          },
          "500": {
            "description": "Opplasting eller AI-uttrekk feilet."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "uploadInboxItem"
      }
    },
    "/v1/companies/{id}/inbox/{iid}": {
      "get": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Hent et innboks-element",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "iid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxItem"
                }
              }
            }
          },
          "404": {
            "description": "Ikke funnet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getInboxItem"
      },
      "/v1/companies/{id}/inbox/count": {
        "get": {
          "tags": [
            "Inbox"
          ],
          "summary": "Tell innboks-bilag (lett count)",
          "description": "Returnerer kun antall innboks-bilag for selskapet. Brukes til badge/notifikasjoner i frontend. Kan filtreres på status.",
          "parameters": [
            {
              "$ref": "#/components/parameters/CompanyId"
            },
            {
              "name": "status",
              "in": "query",
              "required": false,
              "schema": {
                "type": "string",
                "enum": [
                  "parsed",
                  "booked",
                  "error"
                ]
              },
              "description": "Filtrer på status. Uten filter telles alle."
            }
          ],
          "responses": {
            "200": {
              "description": "OK",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/InboxCount"
                  }
                }
              }
            },
            "default": {
              "$ref": "#/components/responses/Problem"
            }
          }
        }
      }
    },
    "/v1/companies/{id}/supplier-invoices": {
      "get": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Liste leverandørfakturaer",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "pending_approval",
                "approved",
                "posted",
                "paid",
                "rejected"
              ]
            }
          },
          {
            "name": "party_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "invoice_date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "invoice_date_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "due_before",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSupplierInvoices"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listSupplierInvoices"
      },
      "post": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Opprett leverandørfaktura manuelt (uten inbox-bilag)",
        "description": "Brukes når du vil registrere en leverandørfaktura uten å laste opp en fil til inbox. Faktura opprettes som `draft` og kan endres frem til den attesteres via `/approve`. Linjefeltet `account_number` resolves nå til konto ved opprettelse (ukjent nummer gir `422 unknown_account`), og `vat_code` resolves til selskapets MVA-kode-id (ADR-019).",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "party_id": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true
                  },
                  "invoice_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "invoice_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "due_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "kid": {
                    "type": "string",
                    "nullable": true
                  },
                  "currency": {
                    "type": "string",
                    "default": "NOK"
                  },
                  "fx_rate": {
                    "type": "number",
                    "default": 1
                  },
                  "net_amount": {
                    "type": "number",
                    "nullable": true
                  },
                  "vat_amount": {
                    "type": "number",
                    "nullable": true
                  },
                  "total_amount": {
                    "type": "number",
                    "nullable": true
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Draft opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierInvoice"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createSupplierInvoice"
      }
    },
    "/v1/companies/{id}/supplier-invoices/{siid}": {
      "get": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Hent leverandørfaktura med linjer og evt. lenket inbox-element/voucher",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "siid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierInvoice"
                }
              }
            }
          },
          "404": {
            "description": "Ikke funnet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getSupplierInvoice"
      },
      "put": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Oppdater header (kun draft)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "siid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "party_id": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true
                  },
                  "invoice_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "invoice_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "due_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "kid": {
                    "type": "string",
                    "nullable": true
                  },
                  "currency": {
                    "type": "string"
                  },
                  "fx_rate": {
                    "type": "number"
                  },
                  "net_amount": {
                    "type": "number",
                    "nullable": true
                  },
                  "vat_amount": {
                    "type": "number",
                    "nullable": true
                  },
                  "total_amount": {
                    "type": "number",
                    "nullable": true
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "supplier_invoice": {
                      "$ref": "#/components/schemas/SupplierInvoice"
                    },
                    "applied": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Ikke draft"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateSupplierInvoice"
      },
      "delete": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Slett draft leverandørfaktura",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "siid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "422": {
            "description": "Kan ikke slette attestert"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteSupplierInvoice"
      }
    },
    "/v1/companies/{id}/supplier-invoices/{siid}/lines": {
      "put": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Erstatt linjer (kun draft)",
        "description": "Erstatter alle linjer på utkastet. Bruk for å korrigere AI-foreslåtte konto/MVA-koder før attestering.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "siid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "lines"
                ],
                "properties": {
                  "lines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "amount"
                      ],
                      "properties": {
                        "description": {
                          "type": "string",
                          "nullable": true
                        },
                        "quantity": {
                          "type": "number",
                          "nullable": true
                        },
                        "unit_price": {
                          "type": "number",
                          "nullable": true
                        },
                        "amount": {
                          "type": "number",
                          "description": "Brutto beløp."
                        },
                        "account_id": {
                          "type": "string",
                          "format": "uuid",
                          "nullable": true
                        },
                        "vat_code": {
                          "type": "string",
                          "nullable": true
                        },
                        "vat_rate": {
                          "type": "number",
                          "nullable": true
                        },
                        "accrual_start_month": {
                          "type": "string",
                          "pattern": "^\\d{4}-(0[1-9]|1[0-2])$",
                          "nullable": true,
                          "description": "Periodisering – startmåned (inkl., format YYYY-MM). Krever også accrual_end_month og accrual_account_number. Må spenne over minst to kalendermåneder.",
                          "example": "2026-02"
                        },
                        "accrual_end_month": {
                          "type": "string",
                          "pattern": "^\\d{4}-(0[1-9]|1[0-2])$",
                          "nullable": true,
                          "description": "Periodisering – sluttmåned (inkl., format YYYY-MM).",
                          "example": "2026-11"
                        },
                        "accrual_account_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "Periodisering – balansekonto som brukes som midlertidig motkonto (typisk 1749 forskuddsbetalt kostnad eller 2960 påløpt kostnad).",
                          "example": "1749"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lines": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Ikke draft"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "replaceSupplierInvoiceLines"
      }
    },
    "/v1/companies/{id}/supplier-invoices/{siid}/approve": {
      "post": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Attestér og generér bokført bilag",
        "description": "Validerer linjer, ekspanderer MVA, sjekker balanse, og oppretter et `posted` voucher (`source='supplier_invoice'`) med leverandørreskontro-postering. Vedlegg fra lenket inbox-element kopieres til voucher-attachments. Setter `status='approved'` og `voucher_id` på leverandørfakturaen.\n\n**Periodisering:** Linjer med `accrual_start_month`, `accrual_end_month` og `accrual_account_number` periodiseres direkte på samme bilag. Original kostnad debiteres som vanlig på fakturadato; deretter legges en rebalansering (kredit kostnad / debet balansekonto) på fakturadato, pluss én linje per kalendermåned i intervallet (siste dag i måneden) som flytter beløpet tilbake fra balansekontoen til kostnadskontoen. Hver månedlinje får sin egen `period_id`, så månedsrapportene treffer riktig periode. Avvises med `422 period_closed` hvis en av månedene ligger i lukket periode.\n\n**Auto-betaling (`auto_payment` i responsen):**\n- `type=\"settled\"` — fakturaen hadde en `payment_method` UTEN ZTL-kobling. Et betalingsbilag bokføres umiddelbart (debet leverandørgjeld / kredit `payment_method.account_id`), AP-reskontro lukkes, fakturaen settes til `paid`.\n- `type=\"ztl_draft\"` — fakturaen hadde en `payment_method` med `ztl_bank_account_id`. I stedet for å auto-bokføre opprettes et `payment_order` i status `draft` som havner i `GET /v1/companies/{id}/payments/pending → awaiting_approval`. Selve betalingsbilaget bokføres FØRST når ZTL bekrefter status `executed` (via `refreshBatchStatus`). Fakturaen forblir `approved` inntil betalingen er gjennomført.\n- `type=\"skipped\"` — payment_order kunne ikke opprettes (f.eks. leverandør mangler bankkonto). Fakturaen er fortsatt attestert; `warning`-feltet forklarer hvorfor.\n- `null` — ingen `payment_method` valgt og selskapet har ingen default. Manuell betaling forventes.\n\nFeltet `auto_settle` er beholdt for bakoverkompatibilitet og er kun satt når `auto_payment.type=\"settled\"`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "siid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Attestert. Returnerer voucher med linjer, `auto_settle` (deprecated) og `auto_payment`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierInvoice"
                }
              }
            }
          },
          "422": {
            "description": "Valideringsfeil: ubalansert, ukjent konto, lukket periode (også for periodiseringsmåneder), mangler leverandør, allerede attestert."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "approveSupplierInvoice"
      }
    },
    "/v1/companies/{id}/accruals": {
      "get": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Liste periodiseringsplaner",
        "description": "Returnerer alle periodiseringsplaner for selskapet (metadata). Hver plan peker til samlebilaget (`voucher_id`) der både rebalansering og månedlige motføringer er postert.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schedules": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "voucher_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "source_type": {
                            "type": "string",
                            "example": "supplier_invoice_line"
                          },
                          "source_id": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true
                          },
                          "balance_account_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "expense_account_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "total_amount": {
                            "type": "number"
                          },
                          "currency": {
                            "type": "string",
                            "example": "NOK"
                          },
                          "start_month": {
                            "type": "string",
                            "example": "2026-02"
                          },
                          "end_month": {
                            "type": "string",
                            "example": "2026-11"
                          },
                          "description": {
                            "type": "string",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listAccruals"
      }
    },
    "/v1/companies/{id}/parties": {
      "get": {
        "tags": [
          "Parter"
        ],
        "summary": "Liste kunder/leverandører",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "is_customer",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "is_supplier",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedParties"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listParties"
      },
      "post": {
        "tags": [
          "Parter"
        ],
        "summary": "Opprett part",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "example": "Acme AS"
                  },
                  "org_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "email": {
                    "type": "string",
                    "nullable": true
                  },
                  "address": {
                    "type": "string",
                    "nullable": true
                  },
                  "is_customer": {
                    "type": "boolean",
                    "default": false
                  },
                  "is_supplier": {
                    "type": "boolean",
                    "default": false
                  },
                  "ar_account_number": {
                    "type": "string",
                    "description": "Kundereskontro-konto. Default 1500 hvis is_customer=true.",
                    "example": "1500"
                  },
                  "ap_account_number": {
                    "type": "string",
                    "description": "Leverandørreskontro-konto. Default 2400 hvis is_supplier=true.",
                    "example": "2400"
                  },
                  "invoice_delivery_method": {
                    "type": "string",
                    "enum": [
                      "manual",
                      "email",
                      "ehf"
                    ],
                    "default": "manual",
                    "description": "Foretrukken sendemetode for salgsfaktura."
                  },
                  "invoice_delivery_email": {
                    "type": "string",
                    "format": "email",
                    "nullable": true,
                    "description": "E-postadresse for fakturasending. Påkrevd når invoice_delivery_method='email'."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Party"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createParty"
      }
    },
    "/v1/companies/{id}/parties/{pid}": {
      "get": {
        "tags": [
          "Parter"
        ],
        "summary": "Hent én part (kunde/leverandør) med saldo og rolle",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK. role = customer | supplier | both | none. Inkluderer ar_account, ap_account, ar_open_total, ap_open_total.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Party"
                }
              }
            }
          },
          "404": {
            "description": "Part ikke funnet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getParty"
      },
      "patch": {
        "tags": [
          "Parter"
        ],
        "summary": "Oppdater part",
        "description": "Oppdaterer valgfrie felter på en part. `ar_account_number`/`ap_account_number` slås opp mot selskapets kontoplan (returnerer 422 ved ukjent konto). Det er ikke tillatt å sette `is_customer=false` eller `is_supplier=false` hvis det finnes åpne reskontroposter av tilsvarende type (409 `has_open_ar`/`has_open_ap`). Returnerer samme berikede shape som GET.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "org_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "nullable": true
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 50,
                    "nullable": true
                  },
                  "address": {
                    "type": "string",
                    "nullable": true
                  },
                  "postal_code": {
                    "type": "string",
                    "nullable": true
                  },
                  "city": {
                    "type": "string",
                    "nullable": true
                  },
                  "is_customer": {
                    "type": "boolean"
                  },
                  "is_supplier": {
                    "type": "boolean"
                  },
                  "ar_account_number": {
                    "type": "string",
                    "nullable": true,
                    "description": "Kontonummer for kundereskontro."
                  },
                  "ap_account_number": {
                    "type": "string",
                    "nullable": true,
                    "description": "Kontonummer for leverandørreskontro."
                  },
                  "invoice_delivery_method": {
                    "type": "string",
                    "enum": [
                      "manual",
                      "email",
                      "ehf"
                    ],
                    "description": "Foretrukken sendemetode for salgsfaktura."
                  },
                  "invoice_delivery_email": {
                    "type": "string",
                    "format": "email",
                    "nullable": true,
                    "description": "E-postadresse for fakturasending. Påkrevd når invoice_delivery_method='email'."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert part.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Party"
                }
              }
            }
          },
          "404": {
            "description": "Part ikke funnet"
          },
          "409": {
            "description": "Kan ikke fjerne rolle pga. åpne reskontroposter."
          },
          "422": {
            "description": "Ugyldig konto eller input."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateParty"
      },
      "delete": {
        "tags": [
          "Parter"
        ],
        "summary": "Slett en part (kunde/leverandør)",
        "description": "Sletter parten kun hvis det IKKE finnes poster i reskontro (subledger_entries) eller bilag i innboksen knyttet til den. Returnerer 409 hvis det finnes referanser.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "404": {
            "description": "Part ikke funnet"
          },
          "409": {
            "description": "Parten har poster i reskontro eller bilag i inbox og kan ikke slettes."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteParty"
      }
    },
    "/v1/companies/{id}/products": {
      "get": {
        "tags": [
          "Produkter"
        ],
        "summary": "Liste produkter",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Søk i navn/SKU"
          },
          {
            "name": "is_active",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    },
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listProducts"
      },
      "post": {
        "tags": [
          "Produkter"
        ],
        "summary": "Opprett produkt",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "sku": {
                    "type": "string",
                    "nullable": true
                  },
                  "name": {
                    "type": "string",
                    "example": "Konsulenttime"
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "unit": {
                    "type": "string",
                    "nullable": true,
                    "example": "time"
                  },
                  "unit_price": {
                    "type": "number",
                    "nullable": true,
                    "example": 1250
                  },
                  "currency": {
                    "type": "string",
                    "default": "NOK"
                  },
                  "vat_code": {
                    "type": "string",
                    "nullable": true,
                    "example": "3"
                  },
                  "income_account_number": {
                    "type": "string",
                    "nullable": true,
                    "description": "Default inntektskonto (typisk 3000-serien). Brukes som default på ordrelinjer.",
                    "example": "3000"
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createProduct"
      }
    },
    "/v1/companies/{id}/products/{pid}": {
      "get": {
        "tags": [
          "Produkter"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "404": {
            "description": "Ikke funnet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getProduct",
        "summary": "Hent produkt"
      },
      "patch": {
        "tags": [
          "Produkter"
        ],
        "summary": "Oppdater produkt",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateProduct"
      },
      "delete": {
        "tags": [
          "Produkter"
        ],
        "summary": "Slett produkt (soft delete hvis brukt)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Soft deleted (is_active=false)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "soft_deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "204": {
            "description": "Slettet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteProduct"
      }
    },
    "/v1/companies/{id}/fiscal-years": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Liste regnskapsår",
        "description": "Returnerer alle regnskapsår for selskapet med status (`open`/`partial`/`closed`) og tilhørende månedsperioder. Krever period.read eller tilsvarende.",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fiscal_years": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FiscalYear"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listFiscalYears"
      },
      "post": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Opprett regnskapsår",
        "description": "Oppretter et regnskapsår (f.eks. 2027) og 12 månedsperioder (jan–des) i én atomisk transaksjon. Returnerer 409 hvis året finnes fra før, 422 hvis periodene overlapper eksisterende år. Krever period.close-rettighet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "year"
                ],
                "properties": {
                  "year": {
                    "type": "integer",
                    "minimum": 2000,
                    "maximum": 2100,
                    "example": 2027
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FiscalYear"
                }
              }
            }
          },
          "409": {
            "description": "Året finnes allerede."
          },
          "422": {
            "description": "Overlappende perioder."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createFiscalYear"
      }
    },
    "/v1/companies/{id}/fiscal-years/{year}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "year",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "Regnskapsår, f.eks. 2027."
        }
      ],
      "get": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Hent ett regnskapsår",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FiscalYear"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getFiscalYear"
      }
    },
    "/v1/companies/{id}/fiscal-years/{year}/close": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "year",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Lukk regnskapsår",
        "description": "Setter alle periodene i året til `closed` med `closed_at`/`closed_by`. Krever period.close-rettighet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Lukket.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FiscalYear"
                }
              }
            }
          },
          "403": {
            "description": "Mangler period.close."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "closeFiscalYear"
      }
    },
    "/v1/companies/{id}/fiscal-years/{year}/reopen": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "year",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "Perioder og regnskapsår"
        ],
        "summary": "Gjenåpne regnskapsår",
        "description": "Setter alle låste perioder i året tilbake til `status = open` OG `lock_level = open`. Perioder som er låst av en innsendt MVA-melding (`vat_locked_at`) hoppes over. `hard_closed`-perioder gjenåpnes kun av tenant-owner; for andre roller hoppes de over. Krever period.close-rettighet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Gjenåpnet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "year": {
                      "type": "integer"
                    },
                    "reopened_periods": {
                      "type": "integer",
                      "description": "Antall perioder som faktisk ble gjenåpnet."
                    },
                    "reopened": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PeriodBrief"
                      }
                    },
                    "skipped_vat_locked": {
                      "type": "array",
                      "description": "Perioder som ikke ble rørt fordi MVA-melding er innsendt.",
                      "items": {
                        "$ref": "#/components/schemas/PeriodBrief"
                      }
                    },
                    "skipped_hard_closed": {
                      "type": "array",
                      "description": "Hardt lukkede perioder som krever owner-rolle.",
                      "items": {
                        "$ref": "#/components/schemas/PeriodBrief"
                      }
                    },
                    "already_open": {
                      "type": "integer",
                      "description": "Antall perioder som allerede var helt åpne."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler period.close."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "reopenFiscalYear"
      }
    },
    "/v1/companies/{id}/sales-invoices": {
      "get": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Liste salgsfakturaer/ordrer",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "sent",
                "posted",
                "paid",
                "cancelled"
              ]
            }
          },
          {
            "name": "party_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "invoice_date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "invoice_date_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "due_before",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SalesInvoice"
                      }
                    },
                    "sales_invoices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SalesInvoice"
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listSalesInvoices"
      },
      "post": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Opprett salgsfaktura (draft) med linjer",
        "description": "Oppretter en kundefaktura i status `draft`. Hver linje må angi `product_id` (henter defaults: pris, mva-kode, inntektskonto) eller eksplisitt `unit_price` + `account_number`. Linjen kan overstyre defaults fra produkt. Beløp beregnes server-side. Bokfør via `POST .../post`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "party_id"
                ],
                "properties": {
                  "party_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Må peke på en part med `is_customer=true`."
                  },
                  "invoice_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "due_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "kid": {
                    "type": "string",
                    "nullable": true
                  },
                  "currency": {
                    "type": "string",
                    "default": "NOK"
                  },
                  "fx_rate": {
                    "type": "number",
                    "default": 1
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "payment_method_id": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true
                  },
                  "lines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "product_id": {
                          "type": "string",
                          "format": "uuid",
                          "nullable": true
                        },
                        "description": {
                          "type": "string",
                          "nullable": true
                        },
                        "quantity": {
                          "type": "number",
                          "default": 1
                        },
                        "unit_price": {
                          "type": "number",
                          "nullable": true,
                          "description": "Hvis null brukes produktets pris."
                        },
                        "vat_code": {
                          "type": "string",
                          "nullable": true,
                          "description": "Hvis null brukes produktets mva-kode."
                        },
                        "account_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "Inntektskonto. Hvis null brukes produktets income_account."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesInvoice"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createSalesInvoice"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}": {
      "get": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Hent salgsfaktura inkl. linjer",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesInvoiceDetail"
                }
              }
            }
          },
          "404": {
            "description": "Ikke funnet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getSalesInvoice"
      },
      "patch": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Oppdater hode (kun draft)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesInvoice"
                }
              }
            }
          },
          "422": {
            "description": "Ikke i status draft"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateSalesInvoice"
      },
      "delete": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Slett (kun draft)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Slettet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteSalesInvoice"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}/lines": {
      "get": {
        "tags": [
          "Salgsfaktura"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lines": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {}
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listSalesInvoiceLines",
        "summary": "Liste linjer på salgsfaktura"
      },
      "post": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Legg til linje (kun draft)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {}
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "addSalesInvoiceLine"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}/lines/{lid}": {
      "patch": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Oppdater linje (kun draft)",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "lid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {}
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateSalesInvoiceLine"
      },
      "delete": {
        "tags": [
          "Salgsfaktura"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "lid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Slettet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteSalesInvoiceLine",
        "summary": "Slett linje på salgsfaktura (kun draft)"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}/post": {
      "post": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Bokfør salgsfaktura",
        "description": "Oppretter et bilag som debiterer kundefordring (AR-konto fra parten, default 1500) og krediterer inntektskonto pr. linje. Utgående mva splittes automatisk fra `vat_code`. Setter `status=posted`, `voucher_id` og `invoice_number` (=`voucher_no`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Bokført — returnerer voucher + ledger lines.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sales_invoice": {
                      "$ref": "#/components/schemas/SalesInvoice"
                    },
                    "voucher": {
                      "$ref": "#/components/schemas/Voucher"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Ugyldig tilstand (allerede bokført, mangler dato, ubalansert)"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "postSalesInvoice"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}/pdf": {
      "get": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Hent faktura-PDF",
        "description": "Genererer (eller henter cachet) PDF for salgsfakturaen. PDF lagres i `voucher-attachments`-bucket og re-genereres automatisk hvis fakturaen er endret. Returnerer `application/pdf` med `Content-Disposition: inline`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "Faktura-PDF (binary)."
                }
              }
            }
          },
          "404": {
            "description": "Fakturaen finnes ikke"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getSalesInvoicePdf"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}/send": {
      "post": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Send faktura på e-post",
        "description": "Sender faktura-PDF til kunden via Resend. Krever `status=posted` (returnerer 422 ellers). Hvis `to` er tom, brukes `parties.email` på kunden — finnes ikke den, returneres 422 `missing_recipient`. Avsender hentes fra `companies.invoice_from_email` (eller en default). Idempotent med `Idempotency-Key`-header. Lagrer historikk i `sales_invoice_deliveries` og oppdaterer `sent_at`/`sent_to`/`delivery_status` på fakturaen. Krever permission `sales_invoice.send`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "to": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email"
                    },
                    "description": "Defaulter til kundens e-post."
                  },
                  "cc": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email"
                    }
                  },
                  "bcc": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email"
                    }
                  },
                  "subject": {
                    "type": "string",
                    "description": "Defaulter til 'Faktura {nr} fra {firma}'."
                  },
                  "message": {
                    "type": "string",
                    "description": "Plain text body. Konverteres også til enkel HTML."
                  },
                  "reply_to": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sendt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sales_invoice_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "delivery_status": {
                      "type": "string",
                      "enum": [
                        "sent"
                      ]
                    },
                    "sent_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "sent_to": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "provider_message_id": {
                      "type": "string"
                    },
                    "delivery": {
                      "$ref": "#/components/schemas/SalesInvoiceDelivery"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Ugyldig tilstand (`invalid_state`, `missing_recipient`)"
          },
          "502": {
            "description": "Resend feilet (`send_failed`)"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "sendSalesInvoice"
      }
    },
    "/v1/companies/{id}/sales-invoices/{ciid}/deliveries": {
      "get": {
        "tags": [
          "Salgsfaktura"
        ],
        "summary": "Liste utsendingsforsøk",
        "description": "Returnerer alle utsendinger for fakturaen (nyeste først), inkludert feilede forsøk.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "ciid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SalesInvoiceDelivery"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listSalesInvoiceDeliveries"
      }
    },
    "/v1/companies/{id}/open-posts": {
      "get": {
        "tags": [
          "Reskontro"
        ],
        "summary": "Åpne poster (kunde- og leverandørreskontro)",
        "description": "Returnerer åpne reskontroposter pr. dato/part/konto. Speiler Tripletex `/ledger/openPost`. Bruk `ledger_type=AR|AP|both` for å filtrere side. `customer_id`/`supplier_id` er deprecated — bruk `party_id` + `ledger_type`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Posterer t.o.m. denne datoen (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "party_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "deprecated": true,
            "description": "Deprecated. Bruk party_id + ledger_type=AR.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "supplier_id",
            "in": "query",
            "deprecated": true,
            "description": "Deprecated. Bruk party_id + ledger_type=AP.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "account_number",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1500"
            }
          },
          {
            "$ref": "#/components/parameters/LedgerTypeQuery"
          },
          {
            "name": "include_closed",
            "in": "query",
            "description": "Default false — kun åpne poster.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedOpenPosts"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listOpenPosts"
      }
    },
    "/v1/companies/{id}/match": {
      "post": {
        "tags": [
          "Reskontro"
        ],
        "summary": "Utlign N reskontroposter (full eller delvis)",
        "description": "Oppretter en utligningshendelse (`close_group`) med én utligningslinje pr. berørt reskontropost. Støtter både full og delvis utligning.\n\n**To former for request-body:**\n- `subledger_entry_ids` (enkel): hver post utlignes med hele sitt gjenstående `open_amount`.\n- `lines` (utvidet): hver post får sitt eget `applied_amount`. Utelates `applied_amount`, brukes hele gjenstående beløp.\n\n**Krav:** alle poster må gjelde samme part, samme `ledger_type` (AR eller AP) og samme valuta, og ha gjenstående beløp. `applied_amount` kan ikke overstige postens `open_amount` (`overapplied`). De anvendte, signerte beløpene (`debit_nok − credit_nok` skalert til anvendt andel) må netter til 0 innenfor gruppen (`not_balanced`).\n\n**Utledede felter:** `open_amount` og `status` på postene settes av databasen ut fra utligningslinjene — en delvis utlignet post får `status = partial`. Speiler Tripletex `PUT /ledger/posting/:closePostings`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Oppgi enten `subledger_entry_ids` eller `lines`.",
                "properties": {
                  "subledger_entry_ids": {
                    "type": "array",
                    "minItems": 2,
                    "maxItems": 200,
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "IDene fra `/open-posts` (feltet `id`). Full utligning av gjenstående beløp pr. post."
                  },
                  "lines": {
                    "type": "array",
                    "minItems": 2,
                    "maxItems": 200,
                    "description": "Per-post anvendt beløp — brukes for delvis utligning.",
                    "items": {
                      "type": "object",
                      "required": [
                        "subledger_entry_id"
                      ],
                      "properties": {
                        "subledger_entry_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "applied_amount": {
                          "type": "number",
                          "description": "Positivt beløp som anvendes mot posten. Default: hele gjenstående `open_amount`."
                        }
                      }
                    }
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Fritekstnotat på utligningshendelsen (revisjonsspor)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet — returnerer `close_group_id`, `matched_count`, `party_id`, `ledger_type`, `currency` og de opprettede utligningslinjene.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchResult"
                }
              }
            }
          },
          "422": {
            "description": "Validering feilet (`party_mismatch` / `ledger_type_mismatch` / `currency_mismatch` / `not_balanced` / `already_closed` / `overapplied`)."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "matchOpenPosts"
      },
      "delete": {
        "tags": [
          "Reskontro"
        ],
        "summary": "Opphev utligning (slett en close group)",
        "description": "Sletter utligningslinjene i gruppen og selve gruppen. Berørte reskontroposter får automatisk `open_amount` tilbake til `original_amount` og `status = open` — med mindre de også inngår i andre utligningsgrupper, som da fortsatt gjelder.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "close_group_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK — postene står åpne igjen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnmatchResult"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "unmatchOpenPosts"
      }
    },
    "/v1/fx-rates/{currency}/{date}": {
      "get": {
        "tags": [
          "Grunndata"
        ],
        "summary": "Valutakurs ≤ dato",
        "parameters": [
          {
            "name": "currency",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 3
            }
          },
          {
            "name": "date",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxRateLookup"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getFxRate"
      }
    },
    "/v1/companies/{id}/reports/trial-balance": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "summary": "Råbalanse",
        "description": "Hvis from/to ikke angis brukes selskapets nyeste regnskapsår automatisk.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra-dato (YYYY-MM-DD). Inkluderer perioder som overlapper intervallet. Standard: start på siste regnskapsår.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til-dato (YYYY-MM-DD). Inkluderer perioder som overlapper intervallet. Standard: slutt på siste regnskapsår.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrialBalanceReport"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getTrialBalanceReport"
      }
    },
    "/v1/companies/{id}/reports/income-statement": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "summary": "Resultatregnskap",
        "description": "Hvis from/to ikke angis brukes selskapets nyeste regnskapsår automatisk.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra-dato (YYYY-MM-DD). Inkluderer perioder som overlapper intervallet. Standard: start på siste regnskapsår.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til-dato (YYYY-MM-DD). Inkluderer perioder som overlapper intervallet. Standard: slutt på siste regnskapsår.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IncomeStatementReport"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getIncomeStatementReport"
      }
    },
    "/v1/companies/{id}/reports/profit-loss": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "summary": "Resultatrapport (eksakt fra-til-dato)",
        "description": "Resultatrapport basert på voucher_date i intervallet [from, to]. Aggregerer ledger_entries direkte – mer presis enn /reports/income-statement som aggregerer på periode-nivå. Standard: nyeste regnskapsår.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra-dato (YYYY-MM-DD) inklusiv på voucher_date.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til-dato (YYYY-MM-DD) inklusiv på voucher_date.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-12-31"
            }
          },
          {
            "name": "include_draft",
            "in": "query",
            "description": "Inkluder utkast-bilag i tillegg til posted (default false).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "monthly",
            "in": "query",
            "description": "Hvis true, inkluderes en `monthly[]`-array med en post pr kalendermåned i intervallet (revenue, expenses, totaler).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK. period, revenue[], expenses[], totals { total_revenue, total_expenses, net_income }, valgfritt monthly[] med {month, revenue[], expenses[], total_revenue, total_expenses, net_income}.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfitLossReport"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getProfitLossReport"
      }
    },
    "/v1/companies/{id}/reports/balance-sheet": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "summary": "Balanse",
        "description": "Hvis from/to ikke angis brukes selskapets nyeste regnskapsår automatisk.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra-dato (YYYY-MM-DD). Inkluderer perioder som overlapper intervallet. Standard: start på siste regnskapsår.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til-dato (YYYY-MM-DD). Inkluderer perioder som overlapper intervallet. Standard: slutt på siste regnskapsår.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceSheetReport"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getBalanceSheetReport"
      }
    },
    "/v1/companies/{id}/reports/vat": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "summary": "MVA-rapport (termin)",
        "description": "Saldo på alle MVA-kontoer for valgt MVA-termin (norske 2-måneders terminer 1..6) eller egendefinert datointervall. Returnerer sum utgående og inngående MVA, samt netto skyldig (positiv) / tilgode (negativ) MVA.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "year",
            "in": "query",
            "description": "År (YYYY). Brukes sammen med term.",
            "schema": {
              "type": "integer",
              "example": 2025
            }
          },
          {
            "name": "term",
            "in": "query",
            "description": "MVA-termin 1..6 (1=jan-feb, 2=mar-apr, 3=mai-jun, 4=jul-aug, 5=sep-okt, 6=nov-des).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 6,
              "example": 1
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Alternativ til year+term. Fra-dato (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Alternativ til year+term. Til-dato (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "include_draft",
            "in": "query",
            "description": "Inkluder utkast-bilag (default false).",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK. period, accounts[] {account_number, account_name, vat_type, debit_nok, credit_nok, balance_nok}, totals {outgoing, incoming, net_payable, status}.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VatReport"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getVatReport"
      }
    },
    "/v1/companies/{id}/reports/ledger": {
      "get": {
        "tags": [
          "Rapporter"
        ],
        "summary": "Hovedbok / kontoutskrift",
        "description": "Drill-down-endepunkt fra saldobalansen. Returnerer alle hovedbokslinjer som matcher filtrene, med løpende saldo, sumtotaler og part-info pr linje (når reskontro). Bruk dette ved klikk på et tall i saldobalansen.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "account_number",
            "in": "query",
            "description": "Kontonummer (unikt pr selskap).",
            "schema": {
              "type": "string",
              "example": "3000"
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Fra-dato (YYYY-MM-DD) på voucher_date.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-01-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Til-dato (YYYY-MM-DD) på voucher_date.",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2025-12-31"
            }
          },
          {
            "name": "party_id",
            "in": "query",
            "description": "Filtrer på en part (kunde og/eller leverandør). Begrenser til partens AR + AP-kontoer.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "description": "Som party_id, men begrenser kun til kundereskontroen (AR-konto).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "supplier_id",
            "in": "query",
            "description": "Som party_id, men begrenser kun til leverandørreskontroen (AP-konto).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 500,
              "maximum": 5000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK. lines[], totals { debit_nok, credit_nok, net_nok }, filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LedgerReport"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getLedgerReport"
      }
    },
    "/v1/companies/{id}/audit-log": {
      "get": {
        "tags": [
          "Audit"
        ],
        "summary": "Audit log for selskapet",
        "description": "Returnerer audit-rader sortert nyest først. Hver rad er beriket med `actor_email` og `actor_name` (slått opp via auth-bruker når `user_id` finnes) samt `actor_source` (`user` | `system` | `cron` | `webhook` | `ai`). Når mulig fylles `summary` med en kort menneskelesbar tekst og `diff` med `{ field: { from, to } }` over felter som faktisk endret seg.\n\n**Leverandørfaktura-hendelser** (alle med `resource_type=\"supplier_invoice\"`):\n- `supplier_invoice.create` / `.update` / `.delete`\n- `supplier_invoice.payment_method.changed`\n- `supplier_invoice.update_lines` (header) + én rad per linje: `.line.created`, `.line.updated`, `.line.deleted`\n- `supplier_invoice.line.accrual.changed`\n- `supplier_invoice.attachment.created` (også fra AI-mottak, da med `actor_source=\"ai\"`)\n- `supplier_invoice.approve` (summary: «Bokført som bilag N»)\n- `supplier_invoice.voucher.linked`",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "resource_type",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "resource_id",
            "in": "query",
            "description": "Filtrer på en konkret ressurs.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "action": {
                            "type": "string",
                            "example": "supplier_invoice.line.updated"
                          },
                          "resource_type": {
                            "type": "string",
                            "example": "supplier_invoice"
                          },
                          "resource_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "user_id": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true
                          },
                          "actor_email": {
                            "type": "string",
                            "nullable": true
                          },
                          "actor_name": {
                            "type": "string",
                            "nullable": true
                          },
                          "actor_source": {
                            "type": "string",
                            "enum": [
                              "user",
                              "system",
                              "cron",
                              "webhook",
                              "ai"
                            ]
                          },
                          "summary": {
                            "type": "string",
                            "nullable": true,
                            "example": "Endret total fra 1 250,00 til 1 500,00"
                          },
                          "diff": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "object",
                              "properties": {
                                "from": {},
                                "to": {}
                              }
                            },
                            "example": {
                              "amount": {
                                "from": 1250,
                                "to": 1500
                              }
                            }
                          },
                          "payload": {
                            "type": "object",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listAuditLog"
      }
    },
    "/v1/companies/{id}/audit-log/{resource_id}": {
      "get": {
        "tags": [
          "Audit"
        ],
        "summary": "Audit log for én ressurs",
        "description": "Som listing-endepunktet, men begrenset til én `resource_id`. Returnerer alle hendelser (oppretting, oppdateringer, linje-events, vedlegg, godkjenning, voucher-kobling) sortert nyest først, med samme beriking (`actor_email`, `actor_name`, `actor_source`, `summary`, `diff`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "resource_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "entries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditLog"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listResourceAuditLog"
      }
    },
    "/v1/tenant/ai-context": {
      "get": {
        "tags": [
          "AI-kontekst"
        ],
        "summary": "Hent tenant-nivå AI-kontekst",
        "description": "Henter regnskapsbyråets felles AI-kontekst (gjelder for alle klienter under tenanten).",
        "parameters": [
          {
            "name": "purpose",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "voucher_interpretation"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiContext"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getTenantAiContext"
      },
      "put": {
        "tags": [
          "AI-kontekst"
        ],
        "summary": "Sett tenant-nivå AI-kontekst",
        "description": "Bare eier eller regnskapsfører (`owner`/`accountant`) kan endre.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "content"
                ],
                "properties": {
                  "content": {
                    "type": "string",
                    "maxLength": 10000,
                    "description": "Fri tekst (markdown). Brukes som system-melding når AI tolker bilag.",
                    "example": "Vi bruker alltid 7790 for diverse småutgifter.\nReise bokføres på 7140 ikke 7100."
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  },
                  "purpose": {
                    "type": "string",
                    "default": "voucher_interpretation"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lagret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiContext"
                }
              }
            }
          },
          "403": {
            "description": "Mangler tilgang"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "setTenantAiContext"
      }
    },
    "/v1/companies/{id}/ai-context": {
      "get": {
        "tags": [
          "AI-kontekst"
        ],
        "summary": "Hent klient-AI-kontekst (lagdelt)",
        "description": "Returnerer global, tenant- og klient-kontekst samt en kombinert versjon. Den kombinerte teksten er det som faktisk sendes som system-melding ved AI-tolkning.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "purpose",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "voucher_interpretation"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiContext"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getCompanyAiContext"
      },
      "put": {
        "tags": [
          "AI-kontekst"
        ],
        "summary": "Sett klient-spesifikk AI-kontekst",
        "description": "Overstyrer/utvider tenant-kontekst for denne klienten.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "content"
                ],
                "properties": {
                  "content": {
                    "type": "string",
                    "maxLength": 10000,
                    "example": "Klienten driver bygg.\nMaterialer fra Onninen → konto 4300.\nFirmabil: drivstoff på 7020."
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  },
                  "purpose": {
                    "type": "string",
                    "default": "voucher_interpretation"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lagret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiContext"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "setCompanyAiContext"
      }
    },
    "/v1/companies/{id}/ai-context/learn": {
      "post": {
        "tags": [
          "AI-kontekst"
        ],
        "summary": "Lær opp AI-kontekst fra et bilag + tilbakemelding",
        "description": "Tar et bilag-id og enten generell tilbakemelding (`feedback`) eller konkrete linje-korreksjoner (`line_corrections`) — gjerne begge. AI henter bilaget, ser hva som ble bokført, og skriver om konteksten slik at samme feil ikke skjer igjen.\n\nMinst én av `feedback` eller `line_corrections` må være satt.\n\n- `apply: false` returnerer kun forslag uten å lagre.\n- `scope: 'tenant'` oppdaterer byrå-kontekst (krever owner/accountant).",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "voucher_id"
                ],
                "properties": {
                  "voucher_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "feedback": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Generell tilbakemelding (valgfri hvis line_corrections er satt).",
                    "example": "Onninen-fakturaer er VVS-materialer. Bruk konto 4300, ikke 6540."
                  },
                  "line_corrections": {
                    "type": "array",
                    "maxItems": 50,
                    "description": "Konkrete linjer som var feil. Identifiser linjen med `ledger_entry_id` (anbefalt) eller `line_index` (0-basert i lest-rekkefølge). Angi `should_be_account` / `should_be_vat_code` og/eller en `note`.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "ledger_entry_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "line_index": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "should_be_account": {
                          "type": "string",
                          "example": "4300",
                          "description": "Riktig kontonummer."
                        },
                        "should_be_vat_code": {
                          "type": "string",
                          "example": "1",
                          "description": "Riktig MVA-kode."
                        },
                        "note": {
                          "type": "string",
                          "maxLength": 500,
                          "example": "VVS-materialer fra Onninen skal alltid hit."
                        }
                      }
                    }
                  },
                  "scope": {
                    "type": "string",
                    "enum": [
                      "company",
                      "tenant"
                    ],
                    "default": "company"
                  },
                  "purpose": {
                    "type": "string",
                    "default": "voucher_interpretation"
                  },
                  "apply": {
                    "type": "boolean",
                    "default": true,
                    "description": "Hvis false: returner forslag uten å lagre."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiContextLearnResult"
                }
              }
            }
          },
          "402": {
            "description": "AI credits exhausted"
          },
          "403": {
            "description": "Mangler tilgang til scope"
          },
          "404": {
            "description": "Bilag ikke funnet"
          },
          "422": {
            "description": "Linje-referanse ugyldig"
          },
          "429": {
            "description": "Rate limited"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "learnAiContext"
      }
    },
    "/v1/companies/{id}/payment-methods": {
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Liste betalingsmetoder",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment_methods": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PaymentMethod"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listPaymentMethods"
      },
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Opprett betalingsmetode",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "account_number"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "example": "DNB Brukskonto"
                  },
                  "account_number": {
                    "type": "string",
                    "description": "Kontonummer i kontoplanen (typisk bank/kasse, f.eks. 1920).",
                    "example": "1920"
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethod"
                }
              }
            }
          },
          "409": {
            "description": "Navn finnes allerede"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createPaymentMethod"
      }
    },
    "/v1/companies/{id}/payment-methods/{pmid}": {
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Hent betalingsmetode",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pmid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethod"
                }
              }
            }
          },
          "404": {
            "description": "Ikke funnet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getPaymentMethod"
      },
      "patch": {
        "tags": [
          "Betaling"
        ],
        "summary": "Oppdater betalingsmetode",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pmid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "account_number": {
                    "type": "string"
                  },
                  "is_active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethod"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updatePaymentMethod"
      },
      "delete": {
        "tags": [
          "Betaling"
        ],
        "summary": "Slett betalingsmetode",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "pmid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Slettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deletePaymentMethod"
      }
    },
    "/v1/companies/{id}/vouchers/{vid}/pay": {
      "post": {
        "tags": [
          "Bilag"
        ],
        "summary": "Marker bilag som betalt",
        "description": "Oppretter et motbilag som registrerer betaling via en betalingsmetode. For leverandørbilag (AP): debet reskontro, kredit betalingskonto. For kundebilag (AR): debet betalingskonto, kredit reskontro. Bokføres automatisk hvis post=true (default). Beløpet kan ikke overstige gjenstående saldo (åpent beløp − allerede bokførte betalinger på samme bilag) — returnerer 422 `overpayment` eller `fully_paid`. For å reversere en feilregistrert betaling, bruk POST /v1/companies/{id}/vouchers/{vid}/reverse på selve betalingsbilaget.",
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyId"
          },
          {
            "name": "vid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "payment_method_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Valgfri. Hvis utelatt brukes selskapets standard betalingsmetode (`is_default=true`). Returnerer 422 `no_default_payment_method` hvis ingen er satt."
                  },
                  "payment_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Standard: i dag."
                  },
                  "amount": {
                    "type": "number",
                    "description": "Standard: gjenstående åpent beløp på reskontroposten."
                  },
                  "counter_account_number": {
                    "type": "string",
                    "description": "Reskontro-/motkonto. Standard: auto-detekteres fra åpen reskontropost på bilaget (største open_amount)."
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "post": {
                    "type": "boolean",
                    "default": true,
                    "description": "Bokfør betalingsbilaget umiddelbart. Sett til false for å la det ligge som kladd."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Betalingsbilag opprettet. Reskontropost lages automatisk på motkonto-linjen. Ved full betaling auto-matches faktura- og betalings-posten i én close_group (`close_group_id` i svaret), og tilhørende `supplier_invoices.status` settes til `paid`. Ved delbetaling reduseres `open_amount` på fakturaposten.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "voucher": {
                      "$ref": "#/components/schemas/Voucher"
                    },
                    "close_group_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "settled": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "subledger_entry_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "applied_amount": {
                            "type": "string"
                          },
                          "open_amount": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Bilag eller betalingsmetode ikke funnet"
          },
          "422": {
            "description": "Ugyldig tilstand: periode stengt (`period_closed`), ingen reskontropost (`no_counter_account`), ingen standard betalingsmetode (`no_default_payment_method`), allerede fullt betalt (`fully_paid`), overbetaling (`overpayment`), eller original ikke bokført (`invalid_state`)."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "payVoucher"
      }
    },
    "/v1/companies/{id}/ztl/connection": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Hent ZTL-tilkobling for selskap",
        "description": "Returnerer status på selskapets ZTL-onboarding (onboarding_id, status, om consent finnes, abonnement). `consent_id` selv eksponeres ikke; bruk feltet `has_consent`.",
        "responses": {
          "200": {
            "description": "OK (connection kan være null hvis ikke startet)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connection": {
                      "type": "object",
                      "properties": {}
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getZtlConnection"
      },
      "post": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Initier onboarding mot ZTL",
        "description": "Starter en ny onboarding for selskapet og returnerer signerings-URL hos ZTL. Selskapet må ha `org_number`. Brukeren sendes til ZTL for signering og redirigeres tilbake til `redirect_url` når ferdig. Status oppdateres via `POST /ztl/connection/refresh`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "redirect_url"
                ],
                "properties": {
                  "redirect_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Hvor brukeren sendes tilbake etter signering."
                  },
                  "country": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2,
                    "description": "ISO-2 landskode. Default: selskapets country_code eller NO."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Onboarding startet; bruk `onboarding_url` for signering.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZtlConnectionResponse"
                }
              }
            }
          },
          "403": {
            "description": "Bare owner/accountant kan koble til ZTL."
          },
          "422": {
            "description": "Mangler `org_number` på selskapet, eller ZTL-feil."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "initZtlConnection"
      }
    },
    "/v1/companies/{id}/ztl/connection/refresh": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Poll status fra ZTL",
        "description": "Henter siste status (`Created`, `AwaitingCustomerAction`, `Processing`, `ManualHandling`, `Accepted`, `Rejected`) fra ZTL og oppdaterer lokal kobling. Kall under aktiv signering eller når brukeren returnerer fra `redirect_url`.",
        "responses": {
          "200": {
            "description": "Status oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connection": {
                      "type": "object",
                      "properties": {}
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Ingen pågående onboarding for selskapet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "refreshZtlConnection",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/v1/companies/{id}/ztl/consent": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Opprett ZTL consent (signering via SCA)",
        "description": "Oppretter en PSD2-consent mot valgt bank og returnerer en SCA-URL (eller QR) som brukeren må signere via BankID/Mobilt BankID. Krever at onboarding er `Accepted`. Etter signering polles status med `GET /ztl/consent` — når status er `VALID` kan `/ztl/accounts/sync` og betalinger brukes.\n\n**Sandbox-tips:** DNB=`DNBANOKK` med `user_id`=`TX99999`, Nordea NO=`NDEANOKK` med en gyldig norsk SSN.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "bic",
                  "user_id",
                  "callback_url"
                ],
                "properties": {
                  "bic": {
                    "type": "string",
                    "description": "Bankens BIC/Swift (f.eks. `DNBANOKK`)."
                  },
                  "user_id": {
                    "type": "string",
                    "description": "Bank-spesifikk bruker-ID (SSN eller test-ID)."
                  },
                  "callback_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL ZTL redirecter til etter signering."
                  },
                  "preferred_sca_method": {
                    "type": "string",
                    "enum": [
                      "Qr",
                      "Redirect"
                    ]
                  },
                  "bank_branch": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Consent opprettet. Bruk `sca_url` for signering.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZtlConsentResponse"
                }
              }
            }
          },
          "422": {
            "description": "Onboarding ikke ferdig, eller validering feilet."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createZtlConsent"
      },
      "get": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Hent consent-status",
        "description": "Poll status (`AWAITING_AUTHORIZATION` → `VALID`/`REJECTED`/`EXPIRED`). Kall etter signering.",
        "responses": {
          "200": {
            "description": "Consent-status hentet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZtlConsentResponse"
                }
              }
            }
          },
          "404": {
            "description": "Ingen consent opprettet for selskapet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getZtlConsent"
      }
    },
    "/v1/companies/{id}/ztl/subscription": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Aktiver/kanseller ZTL-abonnement",
        "description": "Styrer ZTLs faktureringsabonnement for selskapet. Krever owner/accountant.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "activate",
                      "cancel"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Abonnementsstatus oppdatert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "subscription_active": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "setZtlSubscription"
      }
    },
    "/v1/companies/{id}/ztl/accounts": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Liste bankkontoer (cachet lokalt)",
        "responses": {
          "200": {
            "description": "Bankkontoer hentet fra ZTL og lagret lokalt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accounts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ZtlBankAccount"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listZtlAccounts"
      }
    },
    "/v1/companies/{id}/ztl/accounts/sync": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Synk bankkontoer fra ZTL",
        "description": "Henter kontoliste fra ZTL ved hjelp av selskapets consent og upserter til `ztl_bank_accounts`. Krever fullført onboarding (`has_consent=true`).",
        "parameters": [
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Antall kontoer synkronisert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "synced": {
                      "type": "integer"
                    },
                    "total": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Selskapet mangler aktiv consent (`no_consent`)."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "syncZtlAccounts"
      }
    },
    "/v1/companies/{id}/bank-transactions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "List banktransaksjoner",
        "description": "Returnerer banktransaksjoner importert fra ZTL. Sortert nyeste først på `booking_date`. Filtrer på status (`unmatched` | `matched` | `ignored`), konto eller datointervall.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "unmatched",
                "matched",
                "ignored"
              ]
            }
          },
          {
            "name": "ztl_bank_account_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginert liste over banktransaksjoner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedBankTransactions"
                }
              }
            }
          },
          "403": {
            "description": "Mangler `payment.read`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listBankTransactions"
      }
    },
    "/v1/companies/{id}/bank-transactions/sync": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Hent transaksjoner fra ZTL",
        "description": "Henter transaksjoner fra ZTL for en gitt `ztl_bank_account_id`, paginerer gjennom alle sider, lagrer nye rader og hopper over duplikater (unik på `ztl_transaction_id` per konto). Når `auto_match` ikke er `false` kjøres auto-matching umiddelbart etterpå. Krever aktiv consent på selskapets ZTL-tilkobling. Idempotent via `Idempotency-Key`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ztl_bank_account_id"
                ],
                "properties": {
                  "ztl_bank_account_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "date_from": {
                    "type": "string",
                    "format": "date",
                    "description": "Standard: i dag − 90 dager."
                  },
                  "date_to": {
                    "type": "string",
                    "format": "date",
                    "description": "Standard: i dag."
                  },
                  "booking_status": {
                    "type": "string",
                    "enum": [
                      "booked",
                      "pending",
                      "both"
                    ],
                    "default": "booked"
                  },
                  "auto_match": {
                    "type": "boolean",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Synkronisert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankTransactionSyncResult"
                }
              }
            }
          },
          "400": {
            "description": "`account_not_found` eller `ztl_consent_missing`."
          },
          "403": {
            "description": "Mangler `payment.read`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "syncBankTransactions"
      }
    },
    "/v1/companies/{id}/bank-transactions/auto-match": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Kjør auto-matching",
        "description": "Kjører heuristikkene for å matche `unmatched` banktransaksjoner mot `payment_orders`. Strategi: (1) direkte match på `ztl_payment_id`, (2) beløp + valuta + motpartskonto + ±5 dager mot `requested_execution_date`. Matchede ordre settes til `executed`.",
        "responses": {
          "200": {
            "description": "Antall transaksjoner som ble auto-matchet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "matched"
                  ],
                  "properties": {
                    "matched": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler `payment.create`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "autoMatchBankTransactions",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/v1/companies/{id}/bank-transactions/{btid}/match": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "btid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Match manuelt mot en payment_order",
        "description": "Markerer banktransaksjonen som `matched` og kobler den til `payment_order_id`. Setter `match_method=manual`. Payment order settes til `executed`. Returnerer 400 `already_matched` hvis transaksjonen allerede er matchet.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "payment_order_id"
                ],
                "properties": {
                  "payment_order_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Matchet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "matched": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`bank_transaction_not_found`, `already_matched` eller `payment_order_not_found`."
          },
          "403": {
            "description": "Mangler `payment.create`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "matchBankTransaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      },
      "delete": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Fjern match",
        "description": "Setter banktransaksjonen tilbake til `unmatched` og nuller ut matchefelter. Påvirker IKKE statusen på den tilhørende `payment_order` automatisk.",
        "responses": {
          "200": {
            "description": "Match fjernet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "unmatched": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`not_found`."
          },
          "403": {
            "description": "Mangler `payment.create`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "unmatchBankTransaction"
      }
    },
    "/v1/companies/{id}/bank-transactions/{btid}/ignore": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "btid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Ignorer transaksjonen",
        "description": "Markerer banktransaksjonen som `ignored` (f.eks. bankgebyr eller støy som ikke skal matches). Valgfri `note` lagres på raden.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ignorert.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ignored": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler `payment.create`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "ignoreBankTransaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/v1/companies/{id}/payments/pending": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Betalinger til godkjenning",
        "description": "Returnerer to grupper: `awaiting_approval` (payment_orders med status `draft` som venter på å bli satt i en batch til signering, beriket med leverandørfaktura) og `awaiting_signing` (batches som er sendt til ZTL for SCA-signering eller venter på medsignatur, inkludert `signing_url`/`signing_qr`, utløpsdato, `expired`-flag og `last_error` ved medsignatur). Summerer totalbeløp pr valuta pr gruppe. Krever `payment.read`.",
        "responses": {
          "200": {
            "description": "Pending-oversikt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "awaiting_approval": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "awaiting_signing": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "totals": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler `payment.read`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listPendingPayments"
      }
    },
    "/v1/companies/{id}/payments/{pid}/cancel": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "pid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Kanseller betaling",
        "description": "Setter payment_order til `cancelled`. Hvis betalingen allerede er sendt til ZTL (`ztl_payment_id` satt) prøver vi også å kansellere den hos ZTL via consent. Krever `payment.cancel` eller `payment.create`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Kansellert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Feil tilstand eller ZTL avviste kansellering."
          },
          "403": {
            "description": "Mangler permission."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "cancelPayment"
      }
    },
    "/v1/companies/{id}/payment-batches/{bid}/resign": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "bid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Ny signeringslenke for batch",
        "description": "Ber ZTL om en ny SCA-signering for en batch som står i `awaiting_signing` (typisk fordi `signing_url` er utløpt eller bruker avbrøt). Returnerer ny `signing_url`/`signing_qr` og `expires_at`. Krever `payment.sign`. Hvis status er `awaiting_cosigning`, er første signatur allerede akseptert og batchen trenger medsignatur fra en annen bruker.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signing_mode": {
                    "type": "string",
                    "enum": [
                      "redirect",
                      "qr",
                      "queue"
                    ],
                    "description": "Valgfri. Standard er samme som batchen ble opprettet med."
                  },
                  "redirect_url": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ny SCA-signering startet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "batch_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "signing_id": {
                      "type": "string"
                    },
                    "signing_url": {
                      "type": "string",
                      "nullable": true
                    },
                    "signing_qr": {
                      "type": "string",
                      "nullable": true
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`batch_not_found`, `batch_not_signable:<status>`, `ztl_consent_missing` eller ZTL-feil."
          },
          "403": {
            "description": "Mangler `payment.sign`."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "resignPaymentBatch"
      }
    },
    "/v1/companies/{id}/payment-batches/{bid}/cancel": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "bid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Kasser betalingsbatch",
        "description": "Kasserer en batch som står i `draft`, `awaiting_signing`, `awaiting_cosigning` eller `failed` (typisk en orphan uten gyldig `ztl_signing_id`). Hvis batchen har sendt betalinger til ZTL prøves `cancelPayment` på best-effort. Tilhørende `payment_orders` resettes til `draft` slik at de havner tilbake i «Til godkjenning». Krever `payment.cancel`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Batch kassert.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "batch_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "released": {
                      "type": "integer",
                      "description": "Antall payment_orders satt tilbake til draft."
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler `payment.cancel`."
          },
          "404": {
            "description": "`batch_not_found`."
          },
          "409": {
            "description": "`batch_not_discardable:<status>` — batch er ikke i en kasserbar tilstand."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "cancelPaymentBatch"
      }
    },
    "/v1/companies/{id}/parties/{pid}/bank-accounts": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "pid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Parter"
        ],
        "summary": "Liste bankkontoer for en part",
        "description": "Returnerer alle bankkontoer registrert på parten, sortert med primærkonto først.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "bank_accounts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PartyBankAccount"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listPartyBankAccounts"
      },
      "post": {
        "tags": [
          "Parter"
        ],
        "summary": "Legg til bankkonto for en part",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "bank_account_number": {
                    "type": "string",
                    "nullable": true,
                    "description": "BBAN (siffer kun, uten mellomrom)."
                  },
                  "iban": {
                    "type": "string",
                    "nullable": true
                  },
                  "bic": {
                    "type": "string",
                    "nullable": true
                  },
                  "country_code": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2,
                    "nullable": true
                  },
                  "label": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 120
                  },
                  "is_primary": {
                    "type": "boolean",
                    "default": false,
                    "description": "Sett til true for å gjøre dette til primærkonto (opphever forrige primær)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Bankkonto opprettet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartyBankAccount"
                }
              }
            }
          },
          "409": {
            "description": "Kontoen finnes allerede på parten."
          },
          "422": {
            "description": "Verken bank_account_number eller iban er oppgitt."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "addPartyBankAccount"
      }
    },
    "/v1/companies/{id}/parties/{pid}/bank-accounts/{bid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "pid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "bid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "patch": {
        "tags": [
          "Parter"
        ],
        "summary": "Oppdater bankkonto for en part",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "bic": {
                    "type": "string",
                    "nullable": true
                  },
                  "country_code": {
                    "type": "string",
                    "nullable": true
                  },
                  "label": {
                    "type": "string",
                    "nullable": true
                  },
                  "is_primary": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartyBankAccount"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updatePartyBankAccount"
      },
      "delete": {
        "tags": [
          "Parter"
        ],
        "summary": "Slett bankkonto for en part",
        "description": "Returnerer 409 hvis kontoen er i bruk på leverandørfakturaer.",
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "409": {
            "description": "Bankkontoen er i bruk og kan ikke slettes."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deletePartyBankAccount"
      }
    },
    "/v1/companies/{id}/inbox-address/check": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Innboks og leverandørfaktura"
        ],
        "summary": "Sjekk om innboks-e-postadresse er ledig (Bilagsmottak)",
        "description": "Normaliserer og validerer `local`-parameteret, og sjekker om adressen er ledig på tvers av alle selskaper.",
        "parameters": [
          {
            "name": "local",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Ønsket lokal-del av e-postadressen (uten @domene)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sjekk utført.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxEmailCheckResult"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "checkInboxAddress"
      }
    },
    "/v1/companies/{id}/ztl/accounts/{aid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "aid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "ZTL-bankkonto-ID."
        }
      ],
      "get": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Hent ZTL-bankkonto med koblet ledger-konto og betalingsmetode",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZtlBankAccount"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getZtlAccount"
      },
      "patch": {
        "tags": [
          "ZTL-tilkobling"
        ],
        "summary": "Koble ZTL-bankkonto til kontoplan og opprett/oppdater betalingsmetode",
        "description": "Setter `account_number` (eiendelskonto i kontoplanen, typisk 1920) og/eller `is_active`. Kan samtidig opprette eller oppdatere en `payment_method` for ZTL-betalinger.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "account_number": {
                    "type": "string",
                    "nullable": true,
                    "description": "Kontonummer i kontoplanen (typisk 1920). Sett null for å fjerne koblingen."
                  },
                  "is_active": {
                    "type": "boolean"
                  },
                  "payment_method": {
                    "type": "object",
                    "description": "Opprett/oppdater betalingsmetode knyttet til ZTL-kontoen.",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "is_default": {
                        "type": "boolean"
                      },
                      "create_if_missing": {
                        "type": "boolean",
                        "default": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZtlBankAccount"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Konto ikke funnet, inaktiv, eller feil type."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updateZtlAccount"
      }
    },
    "/v1/companies/{id}/payments": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Liste betalingsordre",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "submitted",
                "awaiting_signing",
                "awaiting_cosigning",
                "signed",
                "executed",
                "failed",
                "cancelled"
              ]
            }
          },
          {
            "name": "supplier_invoice_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginert liste.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PaymentOrder"
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler payment.read."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listPayments"
      },
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Opprett betalingsordre fra leverandørfaktura",
        "description": "Henter kreditorinformasjon fra leverandørfakturaen og oppretter en `payment_order` i status `draft`, klar for batch-signering.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "supplier_invoice_id",
                  "debtor_account_id"
                ],
                "properties": {
                  "supplier_invoice_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "debtor_account_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "ZTL-bankkonto-ID (debtor) som betaler."
                  },
                  "requested_execution_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "payment_type": {
                    "type": "string",
                    "enum": [
                      "domestic",
                      "cross_border",
                      "auto"
                    ],
                    "default": "auto"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Betalingsordre opprettet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "$ref": "#/components/schemas/PaymentOrder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validering eller ZTL-feil."
          },
          "403": {
            "description": "Mangler payment.create."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createPayment"
      }
    },
    "/v1/companies/{id}/payments/{pid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "pid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Hent betalingsordre",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "$ref": "#/components/schemas/PaymentOrder"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getPayment"
      },
      "patch": {
        "tags": [
          "Betaling"
        ],
        "summary": "Oppdater betalingsordre (kun draft)",
        "description": "Tillater å endre `requested_execution_date`, `remittance_message` og `remittance_kid` så lenge status er `draft`. Returnerer 422 hvis status ikke er draft. Krever payment.create.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "requested_execution_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "remittance_message": {
                    "type": "string",
                    "maxLength": 140,
                    "nullable": true
                  },
                  "remittance_kid": {
                    "type": "string",
                    "maxLength": 25,
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Oppdatert.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "$ref": "#/components/schemas/PaymentOrder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ugyldig body eller ingen felter å oppdatere."
          },
          "403": {
            "description": "Mangler permission."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Kan kun oppdatere draft-betalinger."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "updatePayment"
      },
      "delete": {
        "tags": [
          "Betaling"
        ],
        "summary": "Kanseller / slett betalingsordre",
        "description": "Setter status til `cancelled`. Hvis ZTL allerede har mottatt ordren, prøves kansellering hos ZTL via `cancelPayment`. Krever payment.cancel eller payment.create.",
        "responses": {
          "200": {
            "description": "Kansellert.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ugyldig tilstand eller ZTL avviste."
          },
          "403": {
            "description": "Mangler permission."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deletePayment"
      }
    },
    "/v1/companies/{id}/payments/{pid}/retry": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "pid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Retry feilet/avvist/kansellert betalingsordre",
        "description": "Resetter en `failed`, `rejected` eller `cancelled` betalingsordre tilbake til `draft` slik at den kan legges i en ny batch. Krever payment.create.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Retry utført.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "$ref": "#/components/schemas/PaymentOrder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Ugyldig status for retry."
          },
          "403": {
            "description": "Mangler permission."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "retryPayment"
      }
    },
    "/v1/companies/{id}/payment-batches": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Liste betalingsbatcher",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginert liste.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PaymentBatch"
                      }
                    },
                    "total_count": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler payment.read."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listPaymentBatches"
      },
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Opprett batch og send til ZTL-signering",
        "description": "Samler et sett `payment_orders` (status `draft`) i én batch, oppretter hver betaling hos ZTL og initierer **batch-SCA-signering** via `POST /api/v2/payments/approve`. Returnerer `signing_url`/`signing_qr` brukeren skal sendes til. Krever `payment.sign`.\n\n**Frontend skal kun sende `payment_order_ids`** — backend håndterer hele ZTL-flyten (opprettelse → approve → henting av `approval_id`). Det finnes ingen separat `/approve`-endepunkt frontend skal kalle først.\n\n**Atomisk:** Batch settes til `awaiting_signing` kun hvis ZTL returnerer en gyldig approval-id. Hvis ZTL feiler, settes batchen til `failed` og tilhørende `payment_orders` rulles tilbake til `draft` slik at brukeren kan prøve igjen. Hvis kun noen betalinger feiler, lister `failures[]` dem og resten går videre.\n\n**Feilkoder:**\n- `all_payments_failed` — ZTL avviste alle betalinger; se `failures[]`.\n- `ztl_approval_missing_id` — ZTL approve-respons manglet kjent approval-id-felt (`approvalId` / `approval_id` / `approvalRef` / `signingId` / `id`). Råresponsen lagres på `payment_batches.last_error` for diagnose.\n- `ztl_consent_missing` — selskapet mangler aktiv PSD2-consent.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "payment_order_ids"
                ],
                "properties": {
                  "payment_order_ids": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    }
                  },
                  "signing_mode": {
                    "type": "string",
                    "enum": [
                      "redirect",
                      "qr",
                      "queue"
                    ],
                    "default": "redirect"
                  },
                  "redirect_url": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              },
              "example": {
                "payment_order_ids": [
                  "b1f1aaaa-0000-0000-0000-000000000001",
                  "c2e2bbbb-0000-0000-0000-000000000002"
                ],
                "signing_mode": "redirect",
                "redirect_url": "https://app.example.no/ztl/callback"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Batch opprettet og signering startet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "batch_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "signing_id": {
                      "type": "string",
                      "description": "Approval-id fra ZTL (uansett underliggende feltnavn)."
                    },
                    "signing_url": {
                      "type": "string",
                      "nullable": true
                    },
                    "signing_qr": {
                      "type": "string",
                      "nullable": true
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                },
                "example": {
                  "batch_id": "9f0a0000-0000-0000-0000-0000000000aa",
                  "signing_id": "appr-2026-06-27-001",
                  "signing_url": "https://sandbox.ztl.no/sca/abc123",
                  "signing_qr": null,
                  "expires_at": "2026-06-27T13:45:00Z",
                  "failures": []
                }
              }
            }
          },
          "400": {
            "description": "`all_payments_failed`, `ztl_approval_missing_id`, `ztl_consent_missing` eller annen ZTL-feil. `failures[]` kan ligge i extensions."
          },
          "403": {
            "description": "Mangler payment.sign."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createPaymentBatch"
      }
    },
    "/v1/companies/{id}/payment-batches/{bid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "bid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Betaling"
        ],
        "summary": "Hent batch med tilhørende betalingsordre",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "batch": {
                      "$ref": "#/components/schemas/PaymentBatch"
                    },
                    "payments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PaymentOrder"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getPaymentBatch"
      }
    },
    "/v1/companies/{id}/payment-batches/{bid}/refresh": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "bid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Betaling"
        ],
        "summary": "Poll ZTL og oppdater batchstatus",
        "description": "Henter siste status fra ZTL for batchen og oppdaterer tilhørende payment_orders. Returnerer ny status. Krever payment.read.\n\n**Status-mapping fra ZTL:**\n- `SIGNED` / `ACCEPTED` / `APPROVED` / `AUTHORIZED` → `signed` (batch er ferdig signert; venter på utførelse hos bank).\n- `PARTLY_SIGNED` / `PARTIALLYSIGNED` / `AWAITING_COSIGNING` → `awaiting_cosigning` (første signatur akseptert; trenger medsignatur fra en annen bruker). `last_error` settes til en menneskelesbar beskjed slik at frontend kan vise hvem som må signere videre.\n- `EXECUTED` / `COMPLETED` / `SETTLED` → `executed` (bokfører betalingsbilag automatisk).\n- `REJECTED` / `FAILED` / `CANCELLED` → `failed` (payment_orders rulles tilbake til `draft`).\n- Øvrige statuser beholder `awaiting_signing`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PsuIpAddress"
          },
          {
            "$ref": "#/components/parameters/PsuUserAgent"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Status oppdatert.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Batch ikke funnet eller ZTL-feil."
          },
          "403": {
            "description": "Mangler payment.read."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "refreshPaymentBatch"
      }
    },
    "/v1/companies/{id}/bank-reconciliations": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Liste bankavstemminger",
        "parameters": [
          {
            "name": "ztl_bank_account_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "approved",
                "reopened"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "reconciliations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BankReconciliation"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listBankReconciliations"
      },
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Opprett eller oppdater utkast til bankavstemmning",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ztl_bank_account_id",
                  "period_id",
                  "closing_balance_bank"
                ],
                "properties": {
                  "ztl_bank_account_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "period_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "closing_balance_bank": {
                    "type": "number",
                    "description": "Bankkontoutskriftens sluttsaldo."
                  },
                  "note": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 2000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Utkast opprettet eller oppdatert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankReconciliation"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "upsertBankReconciliation"
      }
    },
    "/v1/companies/{id}/bank-reconciliations/{rid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "rid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Hent bankavstemmingsrapport",
        "description": "Returnerer fullstendig rapport med matchede og umatchede transaksjoner og differanseanalyse.",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankReconciliationReport"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getBankReconciliation"
      }
    },
    "/v1/companies/{id}/bank-reconciliations/{rid}/approve": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "rid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Godkjenn bankavstemmning",
        "description": "Setter status til `approved`. Krever period.close-rettighet.",
        "responses": {
          "200": {
            "description": "Godkjent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankReconciliation"
                }
              }
            }
          },
          "403": {
            "description": "Mangler period.close."
          },
          "422": {
            "description": "Allerede godkjent eller validering feilet."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "approveBankReconciliation",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/v1/companies/{id}/bank-reconciliations/{rid}/reopen": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "rid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Bankavstemming"
        ],
        "summary": "Gjenåpne bankavstemmning",
        "description": "Setter status tilbake til `reopened` (draft). Krever period.close-rettighet.",
        "responses": {
          "200": {
            "description": "Gjenåpnet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankReconciliation"
                }
              }
            }
          },
          "403": {
            "description": "Mangler period.close."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "reopenBankReconciliation",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/v1/companies/{id}/vat-returns": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "MVA"
        ],
        "summary": "Liste MVA-meldinger",
        "description": "Returnerer alle MVA-meldinger for selskapet, sortert nyeste termin først. Krever report.read.",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vat_returns": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VatReturn"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Mangler report.read."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listVatReturns"
      },
      "post": {
        "tags": [
          "MVA"
        ],
        "summary": "Opprett eller oppdater MVA-meldingsutkast",
        "description": "Bygger `mva_melding_xml` fra bokførte linjer for valgt år/termin. Hvis en draft-rad allerede finnes, oppdateres XML-en. Returnerer 409 om perioden er sendt inn. Krever voucher.post.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "year",
                  "term"
                ],
                "properties": {
                  "year": {
                    "type": "integer",
                    "minimum": 2000,
                    "maximum": 2100
                  },
                  "term": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 6,
                    "description": "MVA-termin 1..6 (norsk 2-måneders)."
                  },
                  "environment": {
                    "type": "string",
                    "enum": [
                      "test",
                      "prod"
                    ],
                    "default": "test"
                  },
                  "include_draft": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Draft oppdatert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VatReturn"
                }
              }
            }
          },
          "201": {
            "description": "Ny MVA-melding opprettet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VatReturn"
                }
              }
            }
          },
          "409": {
            "description": "MVA-melding er allerede sendt inn."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "upsertVatReturn"
      }
    },
    "/v1/companies/{id}/vat-returns/{vrid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "vrid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "MVA"
        ],
        "summary": "Hent MVA-melding (inkl. XML)",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VatReturn"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "getVatReturn"
      },
      "delete": {
        "tags": [
          "MVA"
        ],
        "summary": "Slett draft/failed MVA-melding",
        "responses": {
          "204": {
            "$ref": "#/components/responses/NoContent"
          },
          "409": {
            "description": "Kan ikke slette melding som ikke er draft/failed."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "deleteVatReturn"
      }
    },
    "/v1/companies/{id}/vat-returns/{vrid}/submit": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "vrid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "MVA"
        ],
        "summary": "Send MVA-melding til Skatteetaten via Altinn3",
        "description": "Sender MVA-meldingen til Altinn3-instans-API. Oppdaterer status til `submitted`. Sett `ALTINN_BEARER_TOKEN` i miljøvariabler for reelle kall; uten token brukes dry-run. Krever voucher.post.",
        "responses": {
          "200": {
            "description": "MVA-melding innsendt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "altinn_instance_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validering eller Altinn-feil."
          },
          "403": {
            "description": "Mangler voucher.post."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "submitVatReturn",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/api/mcp": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP Streamable HTTP JSON-RPC (Model Context Protocol)",
        "description": "Implementerer Model Context Protocol (MCP) Streamable HTTP-transport. Aksepterer JSON-RPC 2.0-meldinger. Støtter Supabase JWT og MCP OAuth access token (`mcp_at_...`). Returnerer `WWW-Authenticate` på 401 slik at MCP-klienter (f.eks. Claude Desktop) kan oppdage OAuth-metadata via `/.well-known/oauth-protected-resource`. Tilgjengelige verktøy: `list_companies`, `list_accounts`, `list_vouchers`, `list_inbox`, `trial_balance`, `ledger_entries`, `post_supplier_invoice`, `approve_inbox_item`, `upload_inbox_item`, `create_party`, `submit_vat_return`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "JSON-RPC 2.0-melding.",
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "example": "tools/call"
                  },
                  "id": {
                    "type": [
                      "string",
                      "integer",
                      "null"
                    ]
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC-svar (eller SSE-stream avhengig av transport).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jsonrpc": {
                      "type": "string"
                    },
                    "id": {},
                    "result": {
                      "type": "object",
                      "properties": {}
                    },
                    "error": {
                      "type": "object",
                      "properties": {}
                    }
                  },
                  "description": "JSON-RPC 2.0-svar (MCP)."
                }
              }
            }
          },
          "401": {
            "description": "Mangler eller ugyldig token. `WWW-Authenticate`-header inneholder OAuth discovery-URL.",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "description": "Kun POST støttes (GET/DELETE returnerer Method Not Allowed med JSON-RPC-feil)."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "mcpJsonRpc"
      },
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP — ikke støttet (returnerer 405)",
        "security": [],
        "responses": {
          "405": {
            "description": "Method Not Allowed."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "mcpUnsupportedGet"
      },
      "delete": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP — ikke støttet (returnerer 405)",
        "security": [],
        "responses": {
          "405": {
            "description": "Method Not Allowed."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "mcpUnsupportedDelete"
      }
    },
    "/v1/companies/{id}/ownership-transfers": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Selskaper"
        ],
        "summary": "List eierskifte-forespørsler for selskapet",
        "description": "Synlig for tenants som er kilden eller mottakeren.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnershipTransferListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TenantForbidden"
          },
          "409": {
            "$ref": "#/components/responses/AmbiguousTenant"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "listOwnershipTransfers"
      },
      "post": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Initier eierskifte (to-stegs handshake)",
        "description": "Kun tenant med `relationship='owner'` for selskapet kan initiere. Målet må akseptere via `/v1/ownership-transfers/{tid}/accept`. Delegated-tenanter får `403 not_owner`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to_tenant_id"
                ],
                "properties": {
                  "to_tenant_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "expires_in_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 14
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opprettet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnershipTransfer"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "En pending transfer finnes allerede for dette selskapet"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "createOwnershipTransfer"
      }
    },
    "/v1/ownership-transfers/{tid}/accept": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Mottaker-tenant aksepterer eierskifte (atomisk)",
        "description": "Kaller `accept_ownership_transfer` RPC — én DB-transaksjon: claim + demote gammel eier + promote ny eier. Feiler noe steg, rulles alt tilbake. Kun tenant-owner i mottaker-tenanten kan akseptere.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Akseptert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnershipTransfer"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/TransferExpiredOrResolved"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "acceptOwnershipTransfer"
      }
    },
    "/v1/ownership-transfers/{tid}/decline": {
      "parameters": [
        {
          "name": "tid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "tags": [
          "Selskaper"
        ],
        "summary": "Mottaker-tenant avslår eierskifte (atomisk)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XTenantId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Avslått",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnershipTransfer"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/TransferExpiredOrResolved"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "operationId": "declineOwnershipTransfer"
      }
    }
  },
  "tags": [
    {
      "name": "Autentisering",
      "description": "Innlogging, tokenforvaltning og passord-reset. Kun /v1/auth/*."
    },
    {
      "name": "Tenants og invitasjoner",
      "description": "Berikte medlemskap, tenant-invitasjoner og aksept av invitasjoner."
    },
    {
      "name": "Selskaper",
      "description": "CRUD på selskaper i aktiv tenant + eierskifte (ownership-transfers)."
    },
    {
      "name": "Selskapsmedlemmer",
      "description": "Per-selskap tilgang (company_members)."
    },
    {
      "name": "Tenant-selskaper",
      "description": "Administrativ oversikt og (re)tildeling av selskapstilgang på tenant-nivå (ADR-019). Krever ikke at kalleren selv har company_members-tilgang."
    },
    {
      "name": "Grunndata",
      "description": "Kontoplan, MVA-koder, næringsspesifikasjonskoder og valutakurser."
    },
    {
      "name": "Perioder og regnskapsår",
      "description": "Månedsperioder og regnskapsårsstyring."
    },
    {
      "name": "Bilag",
      "description": "Manuelle bilag med linjer, vedlegg, bokføring, reversering og betaling."
    },
    {
      "name": "Reskontro",
      "description": "Åpne poster og close-group matching."
    },
    {
      "name": "MVA",
      "description": "MVA-meldinger (draft, XML og innsending til Altinn3)."
    },
    {
      "name": "Bilagskontroll",
      "description": "Kvalitetskontroll av bilag (manuelt eller AI): reviews, funn, masse-registrering og kontrollkø."
    },
    {
      "name": "Rapporter",
      "description": "Regnskapsrapporter: råbalanse, resultat, balanse, hovedbok, mva."
    },
    {
      "name": "Bankavstemming",
      "description": "Bankavstemminger og banktransaksjonsimport/-matching fra ZTL."
    },
    {
      "name": "Innboks og leverandørfaktura",
      "description": "AI-tolket innboks, leverandørfakturaer, attestering og periodisering."
    },
    {
      "name": "Salgsfaktura",
      "description": "Salgsfakturaer/ordrer med linjer, PDF, sending og leveringslogg."
    },
    {
      "name": "Produkter",
      "description": "Produkt-/tjenestekatalog for salgsfaktura."
    },
    {
      "name": "Parter",
      "description": "Kunder/leverandører og deres bankkontoer."
    },
    {
      "name": "Betaling",
      "description": "Betalingsordre, batcher og betalingsmetoder."
    },
    {
      "name": "ZTL-tilkobling",
      "description": "ZTL onboarding, consent, subscription og bankkontokobling."
    },
    {
      "name": "Audit",
      "description": "Audit-log for selskap eller ressurs."
    },
    {
      "name": "AI-kontekst",
      "description": "Tenant- og selskaps-kontekst for AI-assistert bokføring."
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol JSON-RPC endpoint. Uversjonert infrastruktur."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Tilgang",
      "tags": [
        "Autentisering",
        "Tenants og invitasjoner",
        "Selskaper",
        "Selskapsmedlemmer"
      ]
    },
    {
      "name": "Oppsett",
      "tags": [
        "Grunndata",
        "Perioder og regnskapsår"
      ]
    },
    {
      "name": "Regnskap",
      "tags": [
        "Bilag",
        "Reskontro",
        "MVA",
        "Rapporter",
        "Bankavstemming"
      ]
    },
    {
      "name": "Flyt",
      "tags": [
        "Innboks og leverandørfaktura",
        "Salgsfaktura",
        "Produkter",
        "Parter"
      ]
    },
    {
      "name": "Betaling",
      "tags": [
        "Betaling",
        "ZTL-tilkobling"
      ]
    },
    {
      "name": "System",
      "tags": [
        "Audit",
        "AI-kontekst",
        "MCP"
      ]
    }
  ]
}