Calculation Modes
Space Invoices supports two standardized document calculation modes.
b2b_standardkeeps the traditional tax-exclusive flow used for most business invoicingb2c_gross_discounttreats discounts as reductions of the customer-facing gross amount, then derives net base and VAT afterward
Use the entity setting when one business should always calculate the same way. Use the request field calculation_mode when a specific document needs to override the entity default.
B2B Standard
Use b2b_standard for classic B2B invoicing where discounts reduce the line amount before VAT is calculated.
Typical flow:
- compute the line subtotal from the net unit price
- apply discounts to that net subtotal
- calculate VAT on the discounted net amount
- sum net, VAT, and gross totals at document level
This is the default mode when nothing is specified.
Exact semantics:
- If you send
price, the line starts fromprice × quantity - Percentage discounts are calculated from the original line subtotal, not from a running balance
- Fixed
amountdiscounts are treated as fixed net amounts - All discount amounts are summed, then subtracted once
- The discounted net line amount is rounded to 2 decimals using half-up rounding
- VAT is then calculated from the rounded net amount
If you send gross_price in b2b_standard:
- start from
gross_price × quantity - calculate discounts from that original gross subtotal
- round the discounted gross result to get
total_with_tax - derive
totalby dividing by(1 + tax_rate)
Example:
price = 100quantity = 2- discount
10% - VAT
22%
Result:
- subtotal =
200.00 - discount =
20.00 - total =
180.00 - total_with_tax =
219.60
B2C Gross Discount
Use b2c_gross_discount when the final payable gross amount is the primary value and discounts should reduce that consumer-facing gross total.
Typical flow:
- start from the gross line subtotal
- apply discounts to the running gross subtotal
- round the discounted gross line total
- derive the net base and VAT from that discounted gross amount
This mode is useful for retail and consumer invoicing where prices are typically shown including VAT.
Exact semantics:
- If you send
gross_price, the line starts fromgross_price × quantity - If you send
price, the line first derives a gross subtotal asprice × quantity × (1 + tax_rate) - Discounts are applied in request order to the running gross subtotal
- Percentage discounts use the current running gross subtotal
- Fixed
amountdiscounts are treated as gross discounts - The final discounted gross line amount becomes
total_with_tax totalis then derived asround_2(total_with_tax / (1 + tax_rate))total_discountis still exposed as a net-equivalent compatibility field, even though the discounts were applied on gross amounts
Example:
gross_price = 122quantity = 1- discount
10% - VAT
22%
Result:
- gross subtotal =
122.00 - gross discount =
12.20 - total_with_tax =
109.80 - total =
90.00 - total_discount =
10.00
Sequential-discount example:
gross_price = 122quantity = 1- discounts:
10%, then5 - VAT
22%
Result:
- start from
122.00 - apply
10%on122.00=12.20, running gross =109.80 - apply fixed
5.00on109.80, running gross =104.80 total_with_tax = 104.80total = 85.90
Choosing The Mode
- Use the entity setting
settings.calculation.default_modefor the normal behavior of a business - Use request
calculation_modeon create endpoints orPOST /documents/calculatewhen a single document should use a different mode - The resolved mode is stored on the document, so rendering and later updates stay consistent
Rounding
All monetary amounts are rounded to 2 decimals using half-up rounding.
- line totals are rounded at line level
- tax amounts are calculated from the rounded line net amount
- document tax totals are aggregated from those rounded line values
Custom Create Endpoints
/custom endpoints still accept caller-supplied totals as authoritative.
- If you omit
calculation_mode, Space Invoices preserves the current pass-through behavior - If you provide
calculation_mode, Space Invoices validates the totals you send against that mode and returns a422error when they do not match
For integrations that need exact alignment before document creation, use POST /documents/calculate with the intended calculation_mode, then send the returned totals to the corresponding /custom endpoint.
For /custom, send these values exactly as calculated:
items[].totalitems[].total_with_tax- document
total - document
total_with_tax - document
total_discount - document
taxes
If you provide calculation_mode, those supplied values must match the selected mode exactly or the request fails with 422.