> ## 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.

# Amounts, roundings and totals

> How to read POS order amounts, round them consistently, and keep your totals coherent when pushing sales and payments into an accounting system.

## Amounts, roundings and totals

When you push POS sales and payments into an accounting system, the numbers have to hold together to the cent: the sum of your revenue lines, VAT and payments must match the order total, and the resulting entry must balance. This guide explains how POS order amounts are exposed by the Unified API and the method we recommend to keep them correct once booked.

The sections below cover the [decimal precision](#1-decimal-precision) of the amounts you receive, the [rounding rule](#2-rounding-rule) to apply, how to [handle VAT](#3-handle-vat-per-rate), how to [split a global discount](#4-splitting-a-global-discount), the POS‑specific points on [tips and payments](#5-tips-and-payments), and the final [reconciliation](#6-reconcile-and-balance) check.

<Info>
  This guide describes the recommended method, not a constraint enforced by the API. When you consume the POS Unified API and write the result yourself into accounting, the rounding responsibility is on your side. If you post through Chift's accounting Unified API, see also [Invoice amounts validation](/developer-guides/api-guides/accounting/invoice-amounts-validation).
</Info>

***

### 🔢 1. Decimal precision

POS amounts may be returned with **more than 2 decimals** in the API response. For example `unit_price`, `total` or `tax_amount` can carry up to 3 decimals, because a net amount is often derived from a gross total or a quantity and that finer precision is preserved.

<Info>
  Treat every monetary value from the API as raw input. Do not assume it is already at 2 decimals, and do not compare two amounts for equality without rounding both first.
</Info>

***

### 🧮 2. Rounding rule

Apply a single, consistent rounding rule to every amount **before** you book it:

**2 decimals**, **round half up**.

Examples:

* a `unit_price` of `2.599` is booked as `2.60`
* a net computed as `2.5950413…` is booked as `2.60`

<Info>
  Avoid the "banker's rounding" (round half to even) that is the default in some languages and libraries, as it will drift against amounts computed the standard commercial way.
</Info>

***

### 🧾 3. Handle VAT per rate

**Reuse the tax amounts provided by the API rather than recomputing them.** Each order exposes its VAT in the `taxes` array, grouped by rate (`tax_rate`, `tax_amount`, `total`), and each line carries its own `tax_amount`. Reusing these values avoids introducing a rounding error that the source system does not have.

If you must derive VAT from a gross (tax‑inclusive) amount and a rate, use the **remainder method** so that net + VAT always equals the exact gross:

```text theme={null}
net = round_half_up(gross / (1 + tax_rate / 100), 2)
vat = gross - net
```

Example: `gross = 3.14`, `tax_rate = 21`

* `net = round(3.14 / 1.21, 2) = 2.60`
* `vat = 3.14 − 2.60 = 0.54`.

Always **reason per VAT rate** (and, if you map revenue to several accounts, per account × rate). Group your lines by `tax_rate` before computing net and VAT — never on a single global total, which would hide compensating rounding differences between rates.

***

### ➗ 4. Splitting a global discount

When a discount applies to the whole order rather than to a single line, spread it across the VAT rates **pro rata** of each rate's base. To avoid a missing cent, give the **remainder to the last bucket** instead of rounding it independently:

```text theme={null}
for each rate except the last:
    share = round_half_up(global_discount * base_rate / base_total, 2)
    allocated += share
last rate:
    share = global_discount - allocated
```

This guarantees that the sum of the per‑rate discount shares equals the global discount exactly.

***

### 💶 5. Tips and payments

Two POS‑specific points determine whether your sales side matches your payments side:

* **Tips are separate from the order total.** `total_tip` (order) and `tip` (payment) are **not** included in `total`. Book them on a dedicated account — do not add them to revenue.
* **Only count valid payments.** Exclude payments whose `status` is `Canceled` or `Failed` before summing.

The order `total` is **tax‑inclusive (TTC)**. Your coherence check on the payment side is:

```text theme={null}
sum(valid payments) + sum(valid tips) + unpaid client account (B2B) = order.total (+ total_tip)
```

The unpaid client account term only appears when an order is invoiced and settled later (B2B); for a fully paid order it is zero.

***

### ✅ 6. Reconcile and balance

After rounding each amount per rate to 2 decimals independently, a residual difference of **a few cents** can remain between the sum of your booked lines (net + VAT) and the order `total`. Book that residue on a **rounding account** so the entry balances (debit = credit):

* a **gain** account for a positive difference (e.g. `758`);
* a **loss** account for a negative difference (e.g. `658`).

<Note>
  A residue of a **cent or two** is normal rounding and belongs on the rounding account. A difference **larger than \~1 €** is not a rounding issue — it signals inconsistent source data. Stop and investigate rather than absorbing it.
</Note>

***

## In short

Round every amount to 2 decimals half‑up, reuse the VAT provided by the API, reason per rate, split global discounts with the remainder on the last bucket, keep tips out of revenue, and close each entry with a reconciliation that sends any residual cent to a rounding account. This is what keeps your accounting totals equal to the original POS amounts.
