Tax: per-location tax lines
You are the seller: you charge the tax, file it and stay responsible for it. Ivora provides the tools. It computes the tax lines you configure on a location and shows them on quotes, bills, receipts, webhooks, the running cost and OCPI. Ivora does not guarantee that a configuration or a preset is legally correct or current. Check what applies to your charging at each location.
A location without tax lines has no tax. Its bills price exactly as before, to the byte.
Tax lines
PUT /v1/tenants/{tenant_id}/locations/{location_id}/tax replaces a location's
configuration. It needs stations:admin: team owners and admins, Ivora staff,
and API keys created with that scope. GET on the same path reads it.
DELETE removes every line. Each change is audit-logged with the caller.
{
"price_mode": "tax_exclusive",
"lines": [
{"name": "GST", "type": "percent", "rate": 5, "registration_number": "123456789RT0001"},
{"name": "QST", "type": "percent", "rate": 9.975, "registration_number": "1234567890TQ0001"}
]
}
| Field | Meaning |
|---|---|
name | Printed on receipts: GST, HST, PST, QST, state sales tax, county, city, EV excise. Unique per location |
type | percent: a percentage of the components the line taxes. per_kwh: minor units of the bill's (its tariff's) currency per kWh delivered; 2.6 is 2.6 cents per kWh in USD |
rate | At most 4 decimal places. percent: 0 to 100. per_kwh: 0 to 1000 |
registration_number | Optional: your registration number for this tax, printed on receipts |
order | Optional: the lines apply in ascending order; lines without one keep their place after those with one |
compound | percent lines: the base includes the earlier lines' tax (Quebec's QST compounded on GST before 2013). Never on the first line or a per_kwh line |
excluded_components | percent lines: tariff components the line does not tax: ENERGY, TIME, PARKING_TIME or FLAT. Empty taxes all of them |
At most 10 lines. An invalid configuration returns 422 tax_invalid with
each problem in details.errors. A replay with the same Idempotency-Key
returns the current configuration.
Price mode
price_mode | Tariff prices | What the driver pays |
|---|---|---|
tax_exclusive (default, the US norm) | Exclude tax | The tariff's total plus every line |
tax_inclusive | Include every line | The tariff's total; the lines are taken out of it |
Calculation
Tax is computed from the tariff snapshot that the bill took when it was created, after the tariff's elements and billing rules:
- The tariff's total is the exact element subtotal after discounts and caps, rounded half up to an integer of minor units, as before.
- A
percentline's base is that total, shared out over the energy, time, idle and flat components in proportion to their exact amounts. Components the line excludes are left out.compoundadds the earlier lines' amounts. - A
per_kwhline is its rate times the kWh delivered. A session with less than 1 Wh delivers none. - Each line is rounded half up to an integer of minor units once.
With tax_exclusive, net_minor is the tariff's total. Each line is computed
on it, and total_minor is net_minor plus tax_minor.
With tax_inclusive, the tariff's total is what the driver pays. Ivora solves
the net before tax exactly and computes each line on it. net_minor is then
total_minor minus the rounded lines, so the parts always add up to the price
shown. When an inclusive price is smaller than its per_kwh tax, the lines are
capped at the price.
Example: a CAD tariff at 0.42 per kWh, at an Alberta location (GST 5 %,
tax_exclusive). For 6.941 kWh, 6.941 × 42 = 291.522 rounds to 292, and GST
5 % of 292 = 14.6 rounds to 15. The driver pays 307 cents.
The shown price, the quote and the bill agree, tax included.
session_limit.amount_minor converts to energy at the per-kWh price with tax
(rate_minor on the limit shows it). max_session_cost_minor caps the price
before tax.
Where tax appears
| Where | What |
|---|---|
| Quotes and simulations | Send location_id on POST .../tariffs/{tariff_id}/quote or .../tariffs/simulate: tax and a total_minor with tax |
| Bills | tax (the frozen configuration, with registration numbers) on every bill at a taxed location; usage.estimated_minor and total_minor include tax; cost_breakdown.tax itemises each line with net_minor, tax_minor and total_minor |
| Charging sessions | The bill, as above. Settlement reports are in the bill's total with tax |
| Webhooks | bill.finalized and the other bill payloads carry the same fields (additive) |
| Running cost | The charger shows the cost with tax; OCPP 1.6 kWhPrice and the final cost text show the per-kWh price with tax |
| OCPI Tariffs | A tariff whose connectors are all at locations with the same lines publishes their combined percentage per component as vat. With tax_inclusive the price is the price before that tax, as OCPI prices exclude VAT. Without location tax, the core tariff's taxRate is published as before |
| OCPI CDRs | A bill-priced CDR's excl_vat is the bill's net_minor and incl_vat is what the driver paid |
per_kwh lines are not a percentage, so an OCPI Tariff cannot express them.
They are included in a CDR's incl_vat. A tariff used at locations whose taxes
differ publishes no vat; its CDRs still carry incl_vat.
A bill freezes the tax of its station's location when it is created. A later
change, or deleting the location, never changes an open or final bill. A bill
without tax has no tax field. Its cost_breakdown has no tax.
Presets
GET /v1/tax-presets (public) lists editable starting points:
- Canada's provinces and territories. Canada has no EV-specific charging tax: GST or HST, plus PST, QST or RST where a province has one.
- The US states with a per-kWh EV charging excise: Iowa, Kentucky and Oklahoma. US sales tax depends on the state, county and city, so it has no preset; add its lines yourself where it applies to charging.
Apply one with {"preset": "CA-AB", "confirm_preset": true}.
confirm_preset says that you checked the preset applies to this location.
Without it the request returns 422 tax_preset_unconfirmed; an unknown ID
returns 422 tax_preset_unknown. The configuration records the preset. Edit
it afterwards with lines, for example to add your registration numbers.
| Preset | Lines (tax_exclusive) |
|---|---|
CA-AB Alberta, CA-NT, CA-NU, CA-YT | GST 5 % |
CA-BC British Columbia | GST 5 % (British Columbia exempts electricity from PST) |
CA-MB Manitoba | GST 5 %, RST 7 % |
CA-SK Saskatchewan | GST 5 %, PST 6 % |
CA-QC Quebec | GST 5 %, QST 9.975 % (not compounding) |
CA-ON Ontario | HST 13 % |
CA-NS Nova Scotia | HST 14 % |
CA-NB, CA-NL, CA-PE | HST 15 % |
US-IA Iowa | Electric fuel excise, 2.6 cents per kWh |
US-KY Kentucky | EV charging excise, 3 cents per kWh |
US-OK Oklahoma | EV charging excise, 3 cents per kWh |
Each preset carries as_of, the date Ivora last reviewed its rates, and a
note.
Not covered
- Automatic tax determination by address (such as Stripe Tax). Ivora applies the lines you configure only.
- Ivora's own usage fee invoices. They are not affected by location tax.



