> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chift.eu/llms.txt
> Use this file to discover all available pages before exploring further.

# Invoice amounts validation and corrections

> Understand how Chift validates invoice amounts and how to handle rounding corrections when using the Unified API.

## Invoice amounts validation and corrections

When you create invoices through the Unified API, Chift checks that your [line items](#line-level-validation) and [totals](#total-level-validation) hold together. Some checks are structural, like requiring at least one line. Others deal with rounding: Chift always stores amounts at 2 decimals. Calculating `untaxed_amount` and `tax_amount` independently can leave your total a cent off from what you intended, especially when you reconcile against a fixed external amount like a payment.

The sections below cover what's validated, what [regroup\_lines](#4-about-regroup_lines) changes, which [calculation](#3-amounts-calculation) formula to use, and how [invoice\_corrections](#5-invoice-corrections) can fix a remaining gap.

***

### 🔍 1. Total-level validation

At the invoice level, the following rules apply:

* **Line count check:** An invoice must contain **at least one line**.
* **Total amount check:** The total must be **greater than or equal to 0**.
* **Sum consistency:**<br />The **sum of all line totals** must match the **invoice total**, within a precision of **4 decimals**.

If there’s a mismatch:

* Difference **> €0.01** → ❌ Rejected
* Difference **≤ €0.01** and **no correction lines provided** → ❌ Rejected
* Difference **≤ €0.01** and [correction lines](#5-invoice-corrections) **are provided** → ✅ Accepted (corrections applied automatically)

***

### 🔍 2. Line-level validation

Chift validates each invoice line individually:

* `untaxed_amount + tax_amount` must equal `total`
* `unit_price × quantity` must equal `untaxed_amount`
* `untaxed_amount × tax_rate` must equal `tax_amount` (exact when `regroup_lines = true`; a tolerance applies when `false`, see [regroup\_lines](#4-about-regroup_lines))

***

### 🧮 3. Amounts calculation

Pick the formula that matches your source data.

#### Invoice-first — your source is the `untaxed_amount`

This is the simple case, and it normally has no rounding issue. The invoice is the original document, built from an `untaxed_amount` the company already set. You compute the `total` from it:

```text theme={null}
total = untaxed_amount × (1 + tax_rate)
```

**Example** — `untaxed_amount = 24.00`, `tax_rate = 21%`:

```text theme={null}
total = 24.00 × 1.21 = 29.04
```

#### Payment-first — your source is the `total`

Use this when the price is defined by its tax-inclusive value, or when the money has already moved for a fixed amount (a card charge, a bank transaction) and you create the invoice afterward to record and reconcile against that `total`. You derive `untaxed_amount` and `tax_amount` from it:

```text theme={null}
untaxed_amount = round(total / (1 + tax_rate), 2)
tax_amount     = total - untaxed_amount
```

Rounding `untaxed_amount` to 2 decimals is part of the formula, not something Chift does for you. Deriving `tax_amount` as the remainder (rather than recomputing it from the rate) is what keeps `untaxed_amount + tax_amount` equal to the exact `total` you reconcile against.

**Example** — `total = 5.00`, `tax_rate = 21%`:

```text theme={null}
untaxed_amount = round(5.00 / 1.21, 2) = round(4.1322…, 2) = 4.13
tax_amount     = 5.00 - 4.13 = 0.87
```

<Tip>
  In the payment-first case, use `regroup_lines = false` to avoid rounding issues that would invalidate the entry total against the payment.
</Tip>

<Warning>
  Some accounting systems recompute each line's `tax_amount` from `untaxed_amount × tax_rate` when they store the entry, so the stored `total` can land a cent off the value you send. Use `invoice_correction` to keep the entry on your legal total (see [Invoice corrections](#5-invoice-corrections)).
</Warning>

***

### ⚙️ 4. About `regroup_lines`

The `regroup_lines (boolean, default: true)` parameter defines whether Chift **groups** lines before validation and posting.

**When regrouping is enabled (**`regroup_lines = true`**):**

* Chift merges lines only when they share the exact same **account number**, **tax code**, **tax rate**, and **analytical distribution** (the `analytic_account` or `analytic_distribution` value), all four at once. If even one of these differs between two lines, Chift keeps them separate and rounds them independently, even if the others match.
* Once merged, Chift rounds each resulting line's `untaxed_amount` and `tax_amount` to 2 decimals independently, then sums them to get that line's `total`.
* The tax check requires `tax_rate × untaxed_amount` to equal `tax_amount` exactly, at 4-decimal precision. No difference is tolerated.
* Chift computes a new total and may introduce an [invoice correction](#5-invoice-corrections) if needed.

**When regrouping is disabled (`regroup_lines = false`):**

* Chift validates each line individually, without merging.
* Chift still rounds each line's `untaxed_amount` and `tax_amount` to 2 decimals independently, then adds them together. **Disabling regrouping does not skip this rounding step.** It only skips the merging of lines.
* The tax check is more permissive here: instead of requiring an exact match, it accepts a tolerance of up to **€0.20** between `tax_rate × untaxed_amount` and `tax_amount` (or **€0.10** if `tax_amount` is zero or negative, e.g. on a credit note).
  <Info>
    This tolerance is what makes `regroup_lines = false` the right setting whenever your `untaxed_amount` and `tax_amount` are calculated to match an external `total` (a payment, a bank transaction) rather than to be mathematically exact against the tax rate. See [Amounts calculation](#3-amounts-calculation) above for when this applies.
  </Info>

👉 **Best practice:**<br />Chift always rounds amounts to 2 decimals per line, regardless of `regroup_lines`:

* Use `regroup_lines = false` when you need your line amounts to **reconcile exactly against a fixed total**;
* Use `regroup_lines = true` only when you want Chift to merge lines sharing the same account/tax code/analytical distribution, and your amounts are already exact relative to the tax rate.

***

### 🧾 5. Invoice corrections

When small rounding differences remain after regrouping or amount calculations, the Unified API can automatically create a **correction line** so that the invoice total matches the sum of all lines exactly.

The correction reconciles the invoice `total` you submit against the **sum of your submitted line totals**, before the entry is posted. It is applied only when that difference is non-zero and at most €0.01 (a larger difference is rejected, see [Total-level validation](#1-total-level-validation)).

You activate this feature by filling in the `invoice_correction` [object](/api-reference/endpoints/accounting/create-salepurchase-entry-multiple-plans#body-invoice-correction) in the invoice creation.

**Provide both a credit and a debit account.** Chift books the correction on the credit account when it is positive and on the debit account when it is negative (reversed for supplier invoices and refunds), with the matching sale or purchase tax code. If only one side is set and the correction needs the other, no correction line is added and the difference is not corrected. This is the most common reason a correction does not appear.

**When the target system recomputes line tax.** Some accounting systems recompute each line's `tax_amount` from `untaxed_amount × tax_rate` and ignore the value you send, which can push the stored `total` a cent off your legal total. To keep the entry on your legal total:

1. set the invoice `total` to your legal total;
2. send each line's `tax_amount` as `untaxed_amount × tax_rate` (the same basis the system recomputes on), so Chift's rounded line total matches the system's;
3. provide `invoice_correction` with both a credit and a debit account.

Chift then adds a 0%-VAT rounding line that brings the entry back to your legal total. If you are unsure whether your system recomputes, use this recipe anyway; it also works when the system does not.

#### Example — `invoice_correction` object

```json theme={null}
"invoice_correction": {
  "sale_invoice_correction_tax_code": "FR_0",
  "purchase_invoice_correction_tax_code": "FR_0",
  "invoice_correction_credit_account_number": "758000",
  "invoice_correction_debit_account_number": "658000"
}
```
