# Microsoft Dynamics 365 Business Central — Accounting API: gotchas

> Canonical URL: https://developers.apideck.com/apis/accounting/microsoft-dynamics-365-business-central/gotchas

## GET /accounting/tax-rates

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`. Business Central returns tax groups without rate values, so `effective_tax_rate` and `total_tax_rate` are both `null` on this connector. Reference the tax by `code` rather than by rate.

## GET /accounting/bills

The `balance` field is not populated for bills. Business Central's API does not expose a
remaining (unpaid) amount on purchase invoices — unlike sales invoices, which back the
invoices resource — so the open remainder of a bill cannot be read. A fully paid bill can
be detected via `status: paid`; partially paid amounts are not visible.

## POST /accounting/bills

When a line omits `tax_rate`, the VAT group configured on the G/L Account Card applies. A foreign vendor's VAT business posting group can zero the line VAT regardless of the `tax_rate` sent.
In U.S.-localized tenants the returned `tax_inclusive` reads `false` even when `true` was sent; line amounts are still computed inclusive of the sent tax rate, so totals match what was sent.
A '400 Bad Request' error "Control 'fieldName' is read-only" means that field's 'editable' property is disabled in Business Central.
`bill_number` and `reference` both map to the single `vendorInvoiceNumber` field, and `bill_number` wins — when both are sent, `reference` is silently discarded. On read both are populated from it and are always identical. Send only `reference` if you need it to survive a round trip.
`notes` is not written — Business Central's purchase invoice has no field it maps to, so the value is silently discarded.

## POST /accounting/invoices

`tax_inclusive` cannot be set on sales documents — the returned value reflects the Customer Card's "Prices Including VAT" setting. When `tax_inclusive: true` is sent for a document stored as tax-exclusive, line `unit_price` is written as its net value so the document totals match the sent tax-inclusive amounts.
When a line omits `tax_rate`, the VAT group configured on the Item or G/L Account Card applies. A foreign customer's VAT business posting group can zero the line VAT regardless of the `tax_rate` sent.
A '400 Bad Request' error "Control 'fieldName' is read-only" means that field's 'editable' property is disabled in Business Central.

## GET /accounting/ledger-accounts

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## GET /accounting/invoice-items

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## POST /accounting/credit-notes

`tax_inclusive` cannot be set on sales documents — the returned value reflects the Customer Card's "Prices Including VAT" setting. When `tax_inclusive: true` is sent for a document stored as tax-exclusive, line `unit_price` is written as its net value so the document totals match the sent tax-inclusive amounts.
When a line omits `tax_rate`, the VAT group configured on the Item or G/L Account Card applies. A foreign customer's VAT business posting group can zero the line VAT regardless of the `tax_rate` sent.
A '400 Bad Request' error "Control 'fieldName' is read-only" means that field's 'editable' property is disabled in Business Central.

## POST /accounting/bill-credit-notes

Setting `status` to `authorised` posts the credit memo; a draft remains editable while a posted one is immutable.
`tax_inclusive` reflects the Vendor Card's "Prices Including VAT" setting and cannot be set directly. When `tax_inclusive: true` is sent for a document stored as tax-exclusive, each line's `unit_price` is written as its net value so the document totals match the sent tax-inclusive amounts.

## PATCH /accounting/bill-credit-notes/{id}

Updating `status` from `draft` to `authorised` posts the credit memo. A posted credit memo is immutable and can no longer be updated.

## DELETE /accounting/bill-credit-notes/{id}

Only a draft (unposted) Business Central Purchase Credit Memo can be deleted. Once a bill credit note has been posted (status `authorised`/`posted`), it can no longer be deleted.

## GET /accounting/customers

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## POST /accounting/suppliers

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central.

## GET /accounting/payments

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## GET /accounting/companies

`meta.total_count` requires `$count=true` OData parameter — not currently implemented. `meta.total_count` will not appear.

## GET /accounting/journal-entries

Journal entries are read from the single general journal batch configured in the required
`journal_entries_journal_batch_name` connection setting. An unfiltered list returns only that
batch's draft (unposted) entries; posted entries are returned when `filter[status]` selects a
posted status (they are read from Business Central's general ledger entries). Journal batches
themselves cannot be listed or selected per request through the unified API.

`currency` and `currency_rate` are not returned. Business Central's API (the v2.0 `journalLine`
entity) exposes no currency fields on journal lines, so amounts are always in the company's
local currency.

## POST /accounting/journal-entries

Employee account type: journal entry lines can reference employees via the `employee` field (use `display_id` for the employee number, or `id` with a GUID which will be resolved automatically). Note: reading back the journal entry will NOT return the employee reference — employee lines are invisible in BC's API for draft entries, and resolve to a GL payable account when posted. Send `ledger_account: {}` alongside the `employee` field to satisfy schema validation.

Journal entries are created in the general journal batch configured in the required `journal_entries_journal_batch_name` connection setting — a different journal/batch cannot be selected per entry or per request.

`currency` and `currency_rate` are not supported: Business Central's API (the v2.0 `journalLine` entity) has no currency fields on journal lines and rejects unknown properties, so amounts are always posted in the company's local currency.

## POST /accounting/purchase-orders

Line items are created together with the purchase order. The type of each line depends on what it references.
A line with `item.id` becomes an item line and a line with `ledger_account.id` becomes a general ledger account
line. Any other line becomes a comment line, including a line that references the item or account only by
`code`. Comment lines keep their `quantity` and `unit_price` but are not included in the order totals. A line
cannot reference both `item.id` and `ledger_account.id`.

`unit_price` is the direct unit cost of the line. `unit_of_measure` is not written, so the item's base unit of
measure is used. A line with a `location_id` is taxed according to that location's tax setup, which can differ
from the other lines on the order.

`status` cannot be set on create. Business Central creates every purchase order as Draft. `sub_total`,
`total_tax` and `total` are calculated from the line items and cannot be set. `po_number` is only accepted when
the company's purchase order number series allows manual numbers. Otherwise Business Central assigns the
number, and a request that sends `po_number` is rejected with "You may not enter numbers manually".

The supplier's default dimensions are added to every line automatically. Sending one of those dimensions again
in a line's `tracking_categories` is rejected with "The dimension set line already exists", so only send
dimensions that are not supplier defaults.

In companies that use Sales Tax, the response returns `tax_inclusive` as `false` even when `true` was sent. The
line amounts are still calculated as tax inclusive, so the totals match what was sent. In these companies
`tax_inclusive` can only be set when the order is created.

A 400 Bad Request error with "Control 'fieldName' is read-only" means the field is set as not editable in
Microsoft Dynamics 365 Business Central. To write to the field, set its 'editable' property to true in
Business Central.

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

`line_items` replaces the order's full set of lines. A line item with an `id` updates that stored line, a line
item without an `id` adds a new line, and any stored line that is left out of `line_items` is removed. Sending
an empty `line_items` array removes every line from the order. To leave the lines as they are, leave out
`line_items` completely. Fields left out of a line item keep their stored values.

New lines follow the same rules as on create. Reference the item by `item.id` or the account by
`ledger_account.id`, but not both. A `code` on its own is not resolved. `unit_of_measure` is not written.

The header is saved first and the line changes are applied after it. If Business Central rejects a line, the
header change and any lines already added or updated stay in place, and the response returns the error for the
rejected line. Lines are only removed after all additions and updates succeed. On an order with
`tax_inclusive: true`, the line prices are saved once more after lines are removed, so an error at that step
can be returned after omitted lines are already gone. Read the order back before retrying.

When an update removes lines, the order's `sub_total`, `total_tax` and `total` can still include the removed
lines until the order is changed again. The returned `line_items` and their amounts are always up to date.

`status` cannot be changed. In companies that use Sales Tax, changing `tax_inclusive` on an existing order is
rejected.

## GET /accounting/goods-receipts

Receipt lines carry no reference to the purchase order line they fulfil, so
`purchase_order_id` and `line_items[].purchase_order` are always null. The header
`po_number` is the only link to the originating purchase order. Business Central also
posts a receipt when a purchase invoice is posted directly, without a purchase order;
those receipts are included in the list and have no `po_number`.

`supplier.id` is null: receipts identify the vendor by number and name only, returned as
`supplier.display_id` and `supplier.display_name`, and that number is not the id used by
`accounting/suppliers`. `quantity_ordered`, `created_at`, `reference`, `notes` and
`location_id` are not available.

Only posted receipts exist in Business Central, so `status` is always `received`. This
resource is read-only.

Only `filter[updated_since]` is supported. Any other filter is rejected with a 400
`UnsupportedFiltersError` rather than being ignored. Likewise only `sort[by]=updated_at` is
supported; `sort[by]=created_at` is rejected with a 400 `UnsupportedSortFieldError`, since
`created_at` is not available on this connector. `meta.total_count` is not populated;
paginate on `meta.cursors.next` until it is null.

## GET /accounting/goods-receipts/{id}

`purchase_order_id`, `line_items[].purchase_order` and `supplier.id` are always null, and
`status` is always `received`; see the list endpoint for the full set of fields this
connector cannot supply. The header `po_number` is the only link to the originating
purchase order, and it is absent for a receipt posted from a purchase invoice without a
purchase order.

## GET /accounting/locations

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## GET /accounting/attachments/{reference_type}/{reference_id}

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central.
Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

For `reference_type` values `journal-entry` and `expense`, `id` is a document number rather
than a single Business Central record — both group every ledger line that shares that
document number into one unified record. Listing attachments for one of these returns every
file attached to any of its lines. If a document number is shared between an unposted/default
grouping used for both `expense` and `journal-entry`, the same attachments can appear under
both `reference_type` values for that document number.

## GET /accounting/bank-accounts

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## GET /accounting/journals

`code` is the value to use for the connection's expense/bill-payment journal batch settings (e.g. an integration configured with journal batch "DEFAULT" posts unposted expenses and bill payments into the journal listed here with that code). `allow_vat` and `currency` are not exposed and are always absent.

## GET /accounting/fiscal-periods

Business Central stores only a period's start date. `end_date` (the day before the next period starts), `fiscal_year` (the calendar year in which the fiscal year ends, so Jul 2025 to Jun 2026 is `2026`; 12 months are assumed for the company's last fiscal year) and `period_number` are derived from the company's full period list, which costs one extra request, and are null if that list cannot be read; `end_date` is always null for the company's last period. `status` and `locked_through` come from the company's General Ledger Setup (Allow Posting From / Allow Posting To), read with one more request; the accounting period's own Closed and Date Locked flags are not used, because they do not stop posting (entries can still be posted to a closed year and are flagged Prior-Year Entry). A period that ends before Allow Posting From or starts after Allow Posting To is `locked`, never `closed`, because User Setup can give individual users a different window; otherwise it is `open`. `locked_through` is the day before Allow Posting From, capped at the period's end date, and null when that day is before the period starts or Allow Posting From is empty. `future` is never returned. If the connection's user cannot read the General Ledger Setup (403), `status` and `locked_through` are null; other failures of that read fail the request. `is_adjustment` and `created_at` are not available.

## GET /accounting/trial-balance

Built from the API v2.0 `trialBalances` entity for the period from the fiscal year start to `end_date`. Balance sheet accounts use Business Central's balance at `end_date`; income and expense accounts use that fiscal year's debits minus credits up to `end_date`. Income statement accounts are identified by their G/L account category (Income, Cost of Goods Sold, Expense); an account without a category is treated as a balance sheet account. The fiscal year start comes from the company's accounting periods: a date before the first fiscal year or after the last fiscal year set up in Business Central returns a `400` (without `filter[end_date]`, a today past the last fiscal year reports as of that year's end), and a company without accounting periods, or without `filter[end_date]` and a fiscal year started yet, returns a `422`. Only posting accounts are listed; heading and total rows are left out. A prior year's income statement result that was never closed to equity is returned as one line named "Result of previous fiscal years (not yet appropriated)" with `line_type` `unappropriated_result` and null `account_id` and `code`; it is derived from the income statement accounts' own cumulative and year-to-date balances. `account_id` is the G/L account's id, the same id the ledger accounts take. `filter[accounting_method]=cash` returns a `400`. `currency` is null. The company is the one selected by `x-apideck-company-id`, else the connection's company. A report whose debits and credits do not balance returns a `502`.
## GET /accounting/tracking-categories

The `limit` parameter is ignored. All tracking categories (parent dimensions and their Standard
dimension values) are always returned in a single response. Non-Standard dimension value types
(Begin-Total, End-Total, Heading, Total) are excluded as they cannot be assigned to transactions.

## GET /accounting/bill-payments

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## POST /accounting/expenses

Employee account type: set `account.type` to `"employee"` and `account.id` to the employee number (or GUID, which will be resolved automatically). Note: reading back the expense will NOT return the employee reference — employee payment lines are invisible in BC's API for draft entries, and resolve to a GL payable account when posted.

Bank account type: when an expense is created with `account.type: "bank_account"` and posted (`status: "posted"`), reading it back returns `account.type: "ledger_account"` with a **different** `account.id`. Business Central records posted transactions against the bank's associated G/L posting account, so the bank account identity is not preserved in the resulting ledger entries. Only `account.type: "ledger_account"` round-trips its `account.id` unchanged. `line_items[].account` is unaffected — expense lines are always G/L accounts and their `account.id` round-trips.

## GET /accounting/expenses/{id}

A posted expense (`status: "posted"`) is read from Business Central's general ledger entries, which carry no bank-account discriminator. Its header `account` is therefore always returned as `account.type: "ledger_account"` — even when the expense was created with `account.type: "bank_account"` — and `account.id` is the bank's associated G/L posting account, not the bank account that was sent on create. `line_items[].account.id` is unaffected. See the create operation's gotcha for the full round-trip behaviour.

## GET /accounting/categories

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.

## GET /accounting/employees

If you encounter a '400 Bad Request' error indicating "Control 'fieldName' is read-only" it means the 'editable' property for this field in Microsoft Dynamics 365 Business Central is currently set to false. To resolve this issue and make the field writable, simply update the 'editable' property to true in Microsoft Dynamics 365 Business Central. Additionally, line item tax rates must be specified by tax rate *code* (e.g., "G3"), not by ID. In U.S.-regionalized Business Central tenants, the `tax_inclusive` field cannot be set to `true`.


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