Structure of a resolved price
Every resolved price follows the same three-level shape:Price type
The top-level key describes what the price is based on:Day
Within a price type, prices are organized by day of week (MONDAY–SUNDAY). If the resolved schedule is identical across all seven days, it is represented once under ALL — this is a size optimization, not a different kind of tariff or a “default” price. Some tariffs may still list seven identical per-day entries instead of collapsing to ALL; consumer logic should handle both shapes.
All calendar values — day of week, time_from, time_to — are expressed in the station’s local timezone, not the customer’s and not UTC, and should be rendered as-is without conversion.
Price slots
Each day contains one or more price slots, applicable over atime_from–time_to window (or the whole day, if unset):
Resolving a price during a session
Locating the correct price slots (by day and time-of-day) determines which price applies. A second, independent dimension determines which tier within it applies once a session is underway:- Calendar time — determines the active price slot (day,
time_from/time_to). - Session-relative time — determines the active tier within that price slot, via
from_minute/to_minute(duration) orfrom_kwh/to_kwh(energy), measured from the start of that session.
null, meaning “no upper limit” — never “zero” or “not set.” A restriction can in principle require both duration and energy bounds simultaneously, though this is uncommon in practice.
Energy and time-based prices are applied differently once a session starts: the applicable energy price is resolved once, at the start of charging, and used for the entire session; time-based pricing instead follows the calendar schedule as it unfolds, so a session spanning a slot-price boundary is billed against each slot in turn. This distinction exists because not all partners reliably send the session updates needed for continuously re-evaluated energy pricing.
Cost calculation is always performed against net_prices (unrounded, VAT-excluded), not user_facing_prices (rounded for display, typically to 2 decimals). A cost computed manually from user_facing_prices may differ slightly from the actual calculated cost due to this rounding — user_facing_prices should be treated as what to display, not what to calculate from.
Points requiring care
A single applicable price is the intersection of three independent dimensions — price type, calendar time, and session-relative state — and all three must be resolved together; applying a duration or energy tier as if it were a calendar boundary produces a plausible but incorrect price. Other points worth noting:- A constant calendar schedule can still combine with a highly tiered session structure — a resolved price is not guaranteed to be a flat value.
net_pricesanduser_facing_pricesdiffer in both tax treatment and unit (time-based prices are per-hour innet_prices, per-minute inuser_facing_prices), not only in VAT. Example: 6 euro/hour excl. VAT -> 0.12 euro/min incl. VAT (20%)to_minute: null/to_kwh: nullmeans unbounded; treating null as falsy can incorrectly drop the final tariff tier, where null typically indicates an unlimited upper bound. This can result in the most expensive tier of the tariff being omitted.
ALL) → time-of-day price slot, in station-local time → session restriction tier (duration and/or energy) for the session in question.
Examples
Full example: constant schedule, tiered by session duration
A station that charges:ALL) whose price slot holds the session tiers:
Duration tier scoped to a specific day and time window
“€0.45/min (after 60 min, 06:00–17:00)”
