> ## 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 e-commerce order amounts, round them consistently, and keep your totals coherent when pushing sales into an accounting system.

## Amounts, roundings and totals

When you push e-commerce sales into an accounting system, the numbers have to hold together to the cent: the sum of your revenue lines, fees and VAT must match the order total, and the resulting entry must balance. This guide explains how e-commerce 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 e-commerce‑specific points on [fees and refunds](#5-fees-and-refunds), 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 e-commerce 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

E-commerce amounts may be returned with **more than 2 decimals** in the API response — for example `unit_price` and `untaxed_amount` can carry up to 4 decimals, because net amounts are frequently derived from a gross total or a discount 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:

* an `untaxed_amount` of `19.6694` is booked as `19.67`
* 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 line (`lines`) and each fee (`other_fees`) exposes its own `untaxed_amount`, `tax_amount`, `total`, `tax_rate` and `tax_id`. Reusing these values avoids introducing a rounding error that the source system does not have. At order level you also have `untaxed_amount`, `tax_amount` and `total`.

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. Note that `tax_rate` itself is returned rounded to 2 decimals (e.g. `21.0`).

***

### ➗ 4. Splitting a global discount

The order exposes `discount_amount` at order level, while line and fee discounts appear in each element's `discounts` array. 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. Fees and refunds

Three e-commerce‑specific points determine whether your revenue matches the order total:

* **Include fees.** `other_fees` (for example shipping) each carry their own `tax_rate` / `tax_id` and base, and are part of the order total. Book them per rate like any revenue line. The `total_without_fees` / `untaxed_amount_without_fees` fields let you separate goods from fees when needed.
* **`total` excludes refunds and returns.** The `total`, `tax_amount` and `untaxed_amount` fields are the order **before** refunds and returns. The `current_total`, `current_tax_amount` and `current_untaxed_amount` fields are the amounts **after** returns and removals. Use the set that matches what you intend to book, and do not mix the two.
* **Treat refunds separately.** `refunded_amount`, `detailed_refunds` and `returns` describe money given back. Book refunds as their own entry (or reverse lines) per VAT rate — never net a refund inside the original sale's VAT base.

<Note>
  The net (HT) of a line is `untaxed_amount`, or equivalently `total − tax_amount` once both are rounded to 2 decimals. Pick one convention and apply it consistently across all lines.
</Note>

***

### ✅ 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 (or the wrong `total` vs `current_total` set). 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, include fees and keep refunds/returns separate (watch `total` vs `current_total`), 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 e-commerce amounts.
