# UBL-DT-01: Write every amount with no more than two decimals

An amount has more than two digits after the decimal point. Every amount element is limited to two, except the item net price and allowances on the price.

- Layer: EN 16931
- Severity: fatal (the document is invalid)
- Topics: Totals, VAT
- Official definition: https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/UBL-DT-01/
- Explanation last updated: 2026-09-24

## The short answer

`UBL-DT-01` fails once for each element whose name ends in `Amount` and whose text has more than two characters after the decimal point. The finding location is that element; write its value with two decimals at most, for example `11.70` instead of `11.700`.

Two kinds of amount are exempt: `cbc:PriceAmount`, and the amounts of an allowance inside `cac:Price`. Everything else, from line amounts to the VAT total, is held to two decimals, and most amounts also have a `BR-DEC` rule of their own that is reported beside this one.

## What the rule checks

The rule picks elements by name, at any depth: anything whose name ends in `Amount`. For each, it takes the text, finds the first decimal point and fails when more than two characters follow. Trailing zeros count, and so does trailing whitespace; when tried, `11.70` followed by a space failed.

The exemptions depend on the element name and its position. The item net price is excluded wherever it appears, and so are `cbc:Amount` and `cbc:BaseAmount` inside `cac:Price/cac:AllowanceCharge`, which carry the price discount and the gross price. The corrected invoice in the recorded example has a net price of `19.995` and validates cleanly.

The VAT total directly under `cac:TaxTotal` has no working decimals rule of its own in this release: the dedicated check for it does not report, so this rule is the only finding for `11.700` there. The VAT total in an accounting currency is in the same position; when tried, `13.456` in a second tax total reported this rule alone.

Where an amount does have its own rule, the two arrive together. When tried, padding all twelve two-decimal amounts of a minimal invoice to three decimals produced twelve `UBL-DT-01` findings and eleven `BR-DEC` findings: one each for every amount except the VAT total.

| Term | Meaning | UBL element |
|---|---|---|
| - | Any element whose name ends in Amount | `At any depth, for example cac:LegalMonetaryTotal/cbc:PayableAmount or cac:InvoiceLine/cac:AllowanceCharge/cbc:Amount` |
| BT-110 | Invoice total VAT amount (the element in the recorded example) | `cac:TaxTotal/cbc:TaxAmount` |
| BT-146 | Item net price (exempt) | `cac:InvoiceLine/cac:Price/cbc:PriceAmount (cac:CreditNoteLine/cac:Price/cbc:PriceAmount in a credit note)` |
| BT-147 | Item price discount (exempt) | `cac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:Amount` |
| BT-148 | Item gross price (exempt) | `cac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:BaseAmount` |

## How an integration ends up here

Possible causes, from the shape of the rule rather than from measured usage:

- A number formatter is configured once, with three or four decimals to suit prices and quantities, and applied to amounts as well.
- Amounts are computed in a type with more precision and written without rounding, so a value like 11.704 reaches the XML.
- A decimal database column with a scale of three or more is written at full scale, turning 11.7 into `11.700`.
- A template engine writes a space or a line break inside the element along with the value.

## How to fix it

1. Use the finding location to identify each element. Every offending amount has its own finding, so the list is complete.
2. Round the value to two decimals where it is calculated, not only where it is formatted, so the totals built on it use the same figure.
3. Format every amount with at most two decimals and no surrounding whitespace. Keep extra decimals only on `cbc:PriceAmount` and on the allowance inside `cac:Price`, where they are allowed.
4. If rounding changed a value, recalculate the totals that depend on it before sending.

## Before and after

These are fragments, not complete documents. The complete synthetic documents they come from are linked below.

Fragment of the failing invoice: the VAT total is written as 11.700

```xml
<cac:TaxTotal>
  <cbc:TaxAmount currencyID="GBP">11.700</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="GBP">58.50</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="GBP">11.70</cbc:TaxAmount>
    <!-- tax category omitted from this fragment -->
  </cac:TaxSubtotal>
  <!-- zero-rated breakdown omitted from this fragment -->
</cac:TaxTotal>
```

Fragment of the corrected invoice: the VAT total written as 11.70, like its breakdown

```xml
<cac:TaxTotal>
  <cbc:TaxAmount currencyID="GBP">11.70</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="GBP">58.50</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="GBP">11.70</cbc:TaxAmount>
    <!-- tax category omitted from this fragment -->
  </cac:TaxSubtotal>
  <!-- zero-rated breakdown omitted from this fragment -->
</cac:TaxTotal>
```

The VAT total directly under `cac:TaxTotal` is written `11.700` in the failing invoice and `11.70` in the corrected one; the breakdowns and all other totals are identical, and the value itself is the same. The failing document reports only `UBL-DT-01`, at `cac:TaxTotal/cbc:TaxAmount`. The EN 16931 decimals rule meant for the VAT total does not fire in this release, and the arithmetic checks compare values, which are equal, so nothing else is reported.

### What the validator reported

- The failing invoice reports **UBL-DT-01**. The corrected document passes every layer with no findings.
  - [Download the failing XML](https://ironfang.uk/finance/rule-examples/UBL-DT-01-invalid.xml)
  - [Download the corrected XML](https://ironfang.uk/finance/rule-examples/invoice-rich.xml)

Recorded on phive 12.1.0 / phive-rules-peppol 4.5.6 / Saxon-HE 12.10, the engine behind the free validator, using synthetic data. A recorded result is regression evidence for these documents; it is not a certification.

## Where it applies

- Applies to UBL `Invoice` and `CreditNote`, and to amounts anywhere in either, including those on `cac:InvoiceLine` and `cac:CreditNoteLine`. When tried, a credit note with a VAT total of `11.700` reported this rule alone, as the invoice does.
- It is reported by the EN 16931 layer although it checks the UBL data type rather than a business term. The XSD layer runs first and accepts `11.700` as a valid decimal, so the problem only surfaces here.
- A value that is not a decimal at all, such as one with a comma or an empty amount element, fails the XSD layer instead, and the business rule layers are skipped.
- An unrounded value is a different case from a padded one. When tried, `11.704` in the VAT total also brought `BR-CO-14`, because it is not the sum of the breakdowns; `11.700` is, and brought nothing else.

## Related rules

- [BR-DEC-20 is reported with this rule when a VAT breakdown tax amount has too many decimals](https://ironfang.uk/docs/finance/rules/BR-DEC-20.md)
- [BR-DEC-23 is reported with this rule when a line net amount has too many decimals](https://ironfang.uk/docs/finance/rules/BR-DEC-23.md)
- [BR-CO-14 checks the value of the VAT total that the recorded example pads](https://ironfang.uk/docs/finance/rules/BR-CO-14.md)
- [PEPPOL-EN16931-R046 checks the price-level discount and gross price, which this rule leaves alone](https://ironfang.uk/docs/finance/rules/PEPPOL-EN16931-R046.md)

## Scope and source

Written for Peppol BIS Billing 3.0.21 (May 2026), EN 16931 1.3.16, as applied to UBL 2.1 Invoice and CreditNote documents. Other profiles, syntaxes and releases can define this identifier differently. Guidance version 2026-09-24.1: source checked 2026-09-24, explanation last updated 2026-09-24.

[The official definition of UBL-DT-01](https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/UBL-DT-01/) carries the normative wording and test. This page is our explanation of it, not a copy.

Guidance does not change the engine verdict. Fixing this finding does not mean the document passes every layer, and validation does not certify legal or tax compliance or transmit a document over Peppol.

## Links

- [This rule as a web page](https://ironfang.uk/docs/finance/rules/UBL-DT-01)
- [Free Peppol invoice validator](https://ironfang.uk/tools/peppol-validator)
- [Rule index](https://ironfang.uk/docs/finance/rules.md)
- [Ironfang Finance API docs](https://ironfang.uk/docs/finance)
- The same rule is available to MCP clients as the tool `finance.rule.get` on https://mcp.ironfang.uk/mcp
