# Visma Netvisor — Accounting API: gotchas

> Canonical URL: https://developers.apideck.com/apis/accounting/visma-netvisor/gotchas

## POST /accounting/invoices

`number` must be numeric: Netvisor stores invoice numbers as integers, so a value such as `INV-001` is rejected.
Each line's `code` must be the code of an existing Netvisor product; letter case is ignored, accents are not. Any other code is rejected as product not found.
Send `status` `draft` (saved as unsent) or `submitted` (saved as open). Any other value, or no `status`, is rejected.
`total` is required: Netvisor needs the invoice amount. Without it the request is rejected with an XML validation error that names `invoicetype`, not the missing amount.

## PATCH /accounting/invoices/{id}

Send the full invoice, including `status` and every line item: a body with only the changed fields is rejected with `400` and nothing is changed.

## PATCH /accounting/invoice-items/{id}

Always send `active` (`true` or `false`): Netvisor rejects an item update without it. Fields you leave out keep their current values, so to change only the name, send `name` and the item's current `active` value.

## POST /accounting/customers

`tax_number` is the customer's Finnish Business ID (Y-tunnus, for example `1234567-1`), not the VAT number (`FI12345678`), and reads back the same way. For a private-person customer Netvisor also accepts a Finnish personal identity code in this field. Netvisor stores no separate display name: `display_name` reads back as the company name.

## POST /accounting/suppliers

`tax_number` is required: send the supplier's Finnish Business ID (Y-tunnus, for example `1234567-1`), not the VAT number (`FI12345678`). It reads back the same way. Netvisor stores no separate display name: `display_name` reads back as the company name.
Also send `currency`, an address with `country`, and at least one phone number or email; Netvisor rejects a supplier without them.

## POST /accounting/payments

Always send `payment_method`, spelled exactly like a payment method set up in the company's Netvisor. Any other value is rejected as an unknown payment method, and so is a payment sent without one.

## POST /accounting/purchase-orders

`supplier.id` must be the supplier's numeric `id` from `GET /suppliers`; the supplier code is rejected with no vendor found (bills accept either).
Send `status` `open`; other values are rejected. Also required: `supplier.address` with `country`, `shipping_address` with `name` and `country`, and `delivery_date`.

## PATCH /accounting/purchase-orders/{id}

Send the full purchase order header, including `status`, the addresses and `delivery_date`: a body with only the changed fields is rejected with `400` and nothing is changed.
In `line_items`, a line with an `id` (as returned by `GET /purchase-orders/{id}`) updates that line, and a line without an `id` is added. Lines you leave out are kept as they are; an update cannot remove a line.

## GET /accounting/fiscal-periods

Netvisor's accounting periods are fiscal years, so every record has `type: year` and `period_number` is null. `fiscal_year` is the calendar year the period ends in. `status` is derived from the company's lock dates: `closed` when the period ends on or before the accounting period lock date (Netvisor blocks changes until the fiscal year is reopened), `locked` when it ends on or before the VAT or accounts payable lock date only (users with a personal VAT override and accountants still post), otherwise `open`; a year the lock date falls inside reads `open`. Netvisor reports no "not yet opened" state, so `future` is never returned. `locked_through` is the latest of the three lock dates, capped at the period's end date, and null when it falls before the period starts. `created_at` and `updated_at` are not available.

## GET /accounting/fiscal-periods/{id}

Netvisor has no endpoint for a single accounting period, so this lists the periods and returns the matching one.

## GET /accounting/trial-balance

Built from Netvisor's account balances on `filter[end_date]` (today by default), on the day before the fiscal year starts and on its first day; the fiscal year comes from Netvisor's accounting periods, so non-calendar fiscal years are supported. Netvisor documents the balance as debit minus credit. Accounts are classified as balance sheet or income statement by Netvisor's `IsCumulative` flag (the Finnish standard chart, classes 1 and 2 as balance sheet, only when an account is missing from the account list). Balance sheet accounts are cumulative to the date; income and expense accounts are reduced to the fiscal year by subtracting their balance on the day before it starts, and the subtracted amount is returned as one extra line, "Result of previous fiscal years (not yet appropriated)" (`line_type` `unappropriated_result`). This assumes Netvisor reports income statement balances cumulatively from the start of the books, which Netvisor does not document and no live response has confirmed yet. The balance on the first day of the fiscal year is compared with the one before it: when income statement balances do not carry over (they reset each fiscal year), the request returns a `502` instead of a report that counts the previous result twice. That check is a heuristic and has not been run against a company with a closed year. Because the extra line is the sum of the subtracted amounts, the debit = credit check only proves that Netvisor's own balances balance (a `502` otherwise). `account_id` is the account's `NetvisorKey`, the id of `GET /ledger-accounts/{id}`. Account group rows are left out so subtotals are not counted twice, as are accounts with a zero balance. Accrual only: `filter[accounting_method]=cash` returns a `400`. Currency is not returned. A `FAILED` answer from Netvisor while reading the periods or accounts is a `401` for failed authentication, a `403` for no access to the company, otherwise a `502`.

[API reference](https://developers.apideck.com/apis/accounting/reference.md) · [Coverage matrix](https://developers.apideck.com/apis/accounting/coverage)
