Rounding differences in UBL invoices

Prevent and handle rounding differences in UBL invoices: PayableRoundingAmount, VAT rounding and VAT-inclusive prices.

One of the most frustrating error messages when sending e-invoices is a rounding difference. The VAT totals do not match the line amounts, or the invoice total deviates by a cent from the calculated sum. The result: the invoice is rejected during validation. This article explains where rounding differences come from and how to prevent or resolve them.

Why do rounding differences occur?

Rounding differences arise from the combination of three factors: multiplication, division and rounding to two decimal places. A few examples:

Unit price with many decimals. A price of 3.333... euros per unit x 3 units = 9.999 euros. Rounded, that is 10.00 euros. But if you first round the unit price to 3.33 and then multiply: 3.33 x 3 = 9.99. A one cent difference.

VAT per line versus VAT per total. If you calculate and round VAT per invoice line and then add them up, the sum may differ from VAT calculated over the total. At 21% VAT on 33.33 euros, that is 7.00 euros (rounded). But 21% of 3 x 33.33 = 21% of 99.99 = 21.00 euros. While 3 x 7.00 = 21.00 euros as well. In this case it matches, but with other amounts it may not.

VAT-inclusive prices. Some sectors (retail, hospitality) work with prices including VAT. The net amount must then be calculated back, which introduces an additional rounding moment.

How UBL handles rounding differences
PayableRoundingAmount

The UBL standard has a special element for rounding differences: PayableRoundingAmount in the LegalMonetaryTotal block. This element absorbs small rounding differences, so the PayableAmount can be a round number:

<cac:LegalMonetaryTotal>
  <cbc:LineExtensionAmount currencyID="EUR">99.99</cbc:LineExtensionAmount>
  <cbc:TaxExclusiveAmount currencyID="EUR">99.99</cbc:TaxExclusiveAmount>
  <cbc:TaxInclusiveAmount currencyID="EUR">120.99</cbc:TaxInclusiveAmount>
  <cbc:PayableRoundingAmount currencyID="EUR">0.01</cbc:PayableRoundingAmount>
  <cbc:PayableAmount currencyID="EUR">121.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>

The 0.01 euro difference is explicitly stated. Validation rules allow a PayableRoundingAmount, provided the difference is small enough (typically a maximum of 1 euro, depending on the profile).

VAT rounding per rate

VAT calculation in a UBL invoice works per VAT rate, not per line. All line amounts with the same VAT rate are summed to form the tax base (TaxableAmount), and VAT is calculated on that. This prevents rounding per line and subsequently getting a cumulative rounding difference.

The formula is:

TaxableAmount = sum of LineExtensionAmount per VAT category
              - AllowanceTotalAmount per VAT category
              + ChargeTotalAmount per VAT category

TaxAmount = TaxableAmount x Percent / 100 (rounded to 2 decimal places)

Important: always calculate VAT on the total tax base per rate, not per line. Per-line VAT calculation is the most common cause of rounding differences.

VAT-inclusive prices

With VAT-inclusive prices, the net amount must be calculated back. The standard approach is:

  1. Calculate the net amount per line: gross / (1 + VAT percentage/100)
  2. Round to 2 decimal places
  3. The LineExtensionAmount is this net amount
  4. The difference between the sum of all net line amounts and the gross total minus VAT may produce a rounding difference
  5. Absorb this with PayableRoundingAmount
<!-- Price including VAT: EUR 12.10 per unit, 3 units -->
<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity unitCode="EA">3</cbc:InvoicedQuantity>
  <cbc:LineExtensionAmount currencyID="EUR">30.00</cbc:LineExtensionAmount>
  <cac:Price>
    <cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
  </cac:Price>
</cac:InvoiceLine>

In this example, the VAT-inclusive price is 12.10 euros. The net amount is 10.00 euros per unit (12.10 / 1.21). Times 3 = 30.00 euros. VAT: 21% of 30.00 = 6.30 euros. Total: 36.30 euros. That matches exactly 3 x 12.10 euros. But with prices that do not divide neatly, a difference arises.

How eConnect handles this

eConnect validates every invoice for internal consistency. If there is a small rounding difference within tolerance, the invoice is accepted. For larger deviations, you receive a clear error message indicating where the difference lies.

The automatic XML repair function of eConnect can in some cases add a missing PayableRoundingAmount if the difference is smaller than the tolerance threshold. But it is always better to handle rounding correctly in your own software.

Practical rules of thumb
  1. Calculate VAT per rate, not per line. First add up all line amounts per VAT rate, then calculate VAT on that total.
  2. Round at the end. Work internally with more than two decimal places and only round when filling in the XML elements.
  3. Use PayableRoundingAmount for the last cent. If despite good rounding a small difference remains, absorb it with this element.
  4. Check the sum. TaxExclusiveAmount + TaxAmount must equal TaxInclusiveAmount. And TaxInclusiveAmount minus PrepaidAmount plus PayableRoundingAmount must equal PayableAmount.
  5. Test with the eConnect Validator. Send your invoice through the validator before sending it. It checks all calculation rules.

Check your invoice