Regulation (EC) 561/2006 is arithmetic. Four and a half hours of driving, then a 45-minute break. Nine hours a day, eleven twice a week, a daily rest of at least eleven hours. Every planning tool worth the name can compute where the clock runs out, and ours does it too.
The regulation says nothing about whether there is anywhere to put the truck.
That is the part dispatchers actually lose sleep over, because the failure mode is not a fine — it is a driver at 21:30 standing in the entrance of a full lorry park, choosing between the hard shoulder and driving on illegally. And it is a genuinely hard problem to plan around, because the map is misleading in a very specific way: the lot does not disappear when it fills up. Every static inventory keeps showing it, at full size, all night.
“Is There a Lorry Park?” Is the Wrong Question
Take Austria, where we have bay-level truth to check the map against.
The static inventory says the ASFINAG motorway and expressway network carries 244 truck-parking sites with 9,185 truck bays. That is the number a coverage map shows, and it is correct. It is also useless after dark, because it describes the concrete, not the availability.
Of those, 85 sites — 5,835 truck bays — publish live occupancy, which we poll every 60 seconds. We have been recording every change for those sites since 30 June 2026: 293,334 observations as of 10 September 2026, of which 127,387 fall inside the trailing thirty days the trend endpoint reads. Bucketing that history by hour of day produces the curve that the static map cannot show you — measured here over the thirty days to 10 September 2026:
| Local time (Austria, CEST) | Truck bays occupied | Avg. free bays per site |
|---|---|---|
| 08:00 – 14:00 | ~39% | ~41 |
| 17:00 | 52.4% | 31.9 |
| 19:00 | 68.4% | 21.2 |
| 21:00 | 76.6% | 15.7 |
| 21:00 – 04:00 (plateau; peak 77.0% at 01:00) | ~76–77% | ~16 |
| 00:00 – 04:00 | ~75–77% | ~16 |
Network-wide occupancy doubles between late morning and nightfall — 38.4% at 11:00 local, 76.6% at 21:00 — and then holds on that plateau until about four in the morning, peaking at 77.0% around 01:00, before it falls away to 57.5% by six. Read as a fleet average, that still sounds survivable: 77% occupied means 23% free, and 16 open bays per site is not nothing.
One arithmetic note, because getting it wrong moves that column by twenty points. Those percentages are truck bays occupied, computed against each site’s truck_spaces. Divide the same free-bay counts by each site’s total capacity instead and the network reads 68–88% occupied all day, which is not a busier network — it is a numerator and a denominator that count different things. 84 of the 85 reporting Austrian sites are mixed sites where the two differ.
That average is the trap. Occupancy does not distribute itself politely across the network; it concentrates, and individual lots go hard to zero:
- 40 of the 86 sites observed in the thirty-day window hit zero free bays at some point.
- At 23:00 local, 22 of the 85 sites observed in that hour had been completely full at least once during the window — at 21:00, 33 of them had, and at 07:00, three. Eight lots record a zero in every single hour from 18:00 to 23:00.
- Take one ordinary lot — Wiener Neustadt, 40 truck bays. Average free bays at 07:00 local: 22.0. At 20:00 local: 5.7. Every hourly bucket from 18:00 to 23:00 local has a recorded minimum of 0.
Wiener Neustadt is not an exceptional site. It is a normal one, and for the entire second half of the evening its honest answer to “can my driver stop here?” is probably not, and you should have known that at dispatch.
Meanwhile the same network at 14:47 local on 10 September looked almost relaxed: zero of 85 sites full, and exactly one lot down to its last two bays. Arnoldstein at the Italian border was sitting at 8% occupancy with 366 of its 402 truck bays open. Both pictures are true. They are six hours apart. A number that is right in the afternoon and wrong at bedtime has to be read live, or it is not worth reading.
Live Occupancy, in the Same /features Call as Everything Else
ASFINAG publishes this as two DATEX II documents: a static ParkingTablePublication describing the sites, and a dynamic ParkingStatusPublication carrying free-space counts. Neither is usable alone — the status document has no geometry, and the table has no occupancy. We join them on parkingRecordReference and publish one feature per site with the live counts folded in:
curl -H "X-API-Key: $KEY" \
"https://api.napspan.com/api/v1/features?type=truck_parking&jurisdiction=AUT"
{
"data": [
{
"id": "AUT-tp-PARK000064",
"source": "AUT",
"jurisdiction": "AUT",
"feature_type": "truck_parking",
"name": "Arnoldstein Zollamt",
"latitude": 46.540813,
"longitude": 13.670096,
"is_active": true,
"properties": {
"truck_parking": true,
"capacity": 431,
"truck_spaces": 402,
"available_spots": 366,
"occupied_spots": 36,
"occupancy_pct": 8,
"occupancy_status": "spacesAvailable",
"opening_status": "open",
"occupancy_updated": "2026-09-10T12:33:34Z"
},
"last_updated": "2026-09-10T12:36:35Z"
}
]
}
Three details in that payload matter more than they look:
-
truck_spacesis the denominator, notcapacity. Arnoldstein has 431 spaces of which 402 take a lorry, andavailable_spotscounts truck bays only. Divide bycapacityand you will quietly under-report how full the truck side is at every mixed site on the network — and that is 84 of the 85 Austrian sites that report. The rule generalises with one branch: usetruck_spaceswhere the feed publishes it, andcapacitywhere it does not. Austria stampstruck_spaceson all 244 of its sites; the German federal feed stamps it on none, because its lorry-parking records are truck-only andcapacityalready is the truck figure. -
available_spots: 0is a fact, not a gap. It means known full. A site with no live feed omits the field entirely. Those two states must not collapse into one in your code — treat “absent” as unknown and “0” as closed to you. -
occupancy_updatedis the count’s own timestamp, separate fromlast_updated, so you can age out a stale reading on your own threshold rather than trusting our poll cycle.
And the jurisdiction code is ISO 3166-1 alpha-3. ?jurisdiction=AUT, never AT — the two-letter form is not an alias, it returns an empty result set.
The Trend: “Is This Lot Typically Full at My ETA?”
A live count answers a question about now. Dispatch plans a stop for six hours from now, when the live count will have changed. That gap is what the per-hour history is for, and it comes back on the feature-detail endpoint:
curl -H "X-API-Key: $KEY" \
"https://api.napspan.com/api/v1/features/AUT-tp-PARK000402/details"
{
"data": { "id": "AUT-tp-PARK000402", "name": "Wr. Neustadt", ... },
"availability_trend": [
{ "hour": 5, "avg_available": 22.0, "avg_capacity": 71, "samples": 77, "low_samples": 0 },
{ "hour": 12, "avg_available": 15.2, "avg_capacity": 71, "samples": 72, "low_samples": 0 },
{ "hour": 18, "avg_available": 5.7, "avg_capacity": 71, "samples": 41, "low_samples": 0 },
{ "hour": 20, "avg_available": 2.0, "avg_capacity": 71, "samples": 22, "low_samples": 0 }
]
}
Twenty-four buckets, built from the trailing thirty days of recorded occupancy for that specific lot. It is the difference between “there are two bays free right now” and “this lot has been down to single digits every evening for a month” — and only the second one is actionable at 14:00 when you are deciding where the driver sleeps.
Three things to know before you plot it. Hours are UTC; Austria ran at UTC+2 across this window, so bucket 18 is 20:00 on the driver’s dashboard clock — localize before you show it to a human. samples is there to be read: buckets are recorded on change, so a thin bucket deserves less confidence than a fat one. We publish the count rather than smoothing it away.
And the third is the one that will silently skew a chart: avg_capacity is the site’s total capacity, while avg_available counts truck bays only. Wiener Neustadt has 40 truck bays inside 71 total spaces, which is why every bucket above reads avg_capacity: 71. Computing 1 - avg_available / avg_capacity is therefore not this lot’s truck occupancy — it mixes the two counts and reads about twenty points too full. Take the denominator from the feature’s truck_spaces and use avg_capacity only for what it is: the size of the whole site. It is the same trap as the live payload, one field name further along, and the fact that the two numbers sit side by side in the same object is exactly what makes it easy to miss.
Where It Actually Belongs: On the Route, Next to the Break
Querying a lot by id is the debugging path. The one that changes an evening is that occupancy arrives already attached to the route, and to the break the regulation demands.
Send a normal truck route to POST /api/v1/routing/route with include_features: ["truck_parking"], and parking comes back in the features[] channel — distinct from hazard warnings[], opt-in, and costing nothing when you do not ask for it:
{
"features": [
{
"type": "truck_parking",
"name": "Wr. Neustadt",
"distance_along_route_m": 184000,
"detour_m": 240,
"side": "right",
"available_spots": 3,
"capacity": 40,
"as_of": "2026-07-30T18:02:11Z",
"source": "AUT",
"geometry": { "type": "Point", "coordinates": [16.2, 47.8] }
}
]
}
Then add an hos block with the driver’s clock and ruleset: "eu_561", and the response gains an hos[] projection: where the break falls, and which parking is reachable before the limit rather than after it. Where a feed publishes live occupancy, two things follow that a static inventory can never do:
- Reachable parking is ordered by open spaces, so the first suggestion is the one most likely to still have room, not merely the nearest concrete.
-
The stop is flagged
feasible: falsewhen every reachable lot reports full. That is the alert worth having. It fires at planning time, in an API response, hours before it would otherwise arrive as a phone call from a lay-by.
It rides the same request as the corridor’s truck bans and VMS signs, its toll costs, its border queues, and the 561/2006 break plan itself. One call returns a drivable truck route, the rules that would stop it, what it costs, where the driver must legally rest — and whether there will be a bay there when they arrive.
What This Data Does Not Do
The honest limits are part of the product, so here they are without decoration.
-
Most national feeds publish inventory, not occupancy. Slovenia, the Netherlands, Bavaria and Latvia all hand us sites and capacities with no availability whatsoever, and the same is true of most of the general
parkingfeeds. Two feeds are the exception, and the larger one is German: the federal motorway lorry-parking layer carries live counts on 1,759 of its 1,858 sites, twenty times Austria’s reporting network, and it is live in the API in the sametruck_parkingschema. This post is built on Austria anyway, for a reason worth stating plainly: ASFINAG’s terms are a confirmed CC BY 4.0, while the German federal licence variant is still being verified, and we would rather anchor a worked example on the layer whose redistribution terms we have finished checking. Query both; weigh the German one accordingly until we can say more. -
Even in Austria it is 85 of 244 sites. The other 159 are real lots that appear with capacity and no counts. Your UI needs a third state — free / full / not reporting — and the absence of
available_spotsis what selects it. - Thirty days of history is thirty days, and it is a moving window. The Austrian series starts 30 June 2026 — 293,334 observations by 10 September — but the trend endpoint reads only the trailing thirty days, so the record has already outgrown the window and what you get back today is a summer month, not the whole series. The difference is not academic: in the thirty days to 30 July, 57 of the 86 lots had hit zero free bays and 47 of the sites observed at 23:00 had been full at some point; in the thirty days to 14 August those figures are 40 and 29, and in the thirty days to 10 September, 40 and 22. Same network, same endpoint, weeks apart. Use the trend as a base rate for the season you are in, and re-pull it rather than caching a number from last month.
- A free bay is not a reserved bay. Nothing here books anything. It tells you what the operator reported and when, which is what you need to choose between two lots — not a guarantee that the space survives the next twenty minutes.
- The trend is a prior, not a prediction. An hour-of-day average over thirty days is a solid base rate and it is blind to the specific Thursday your driver is having. Use it to rank candidates and to know when the network tightens; use the live count for the final call.
The Common Thread
This is the same shape as the five road-data problems every cross-border European fleet hits. The information exists. A public authority publishes it, properly, under an open licence. It arrives split across two DATEX II documents that have to be joined on a reference key, in a national profile, on its own cadence — and doing that once per country, forever, is a maintenance commitment that competes with the product you actually sell.
NAPSPAN does that join once. Austrian bay counts arrive in the same truck_parking schema as every other parking feed in the system, filterable by jurisdiction, carried on the route beside the tolls and the rest breaks, served from Europe, and licence-classified before it ships. The Austrian data is published by ASFINAG under CC BY 4.0 — Datenquelle: ASFINAG — licensed under CC BY 4.0 — and that credit travels with every record we hand you.
Try It
-
API docs —
/featureswithtype=truck_parking,/features/{id}/detailsfor the trend, andPOST /routing/routewithinclude_features - Live map — the Austrian network as it stands right now
- Free API key — no card, 14-day trial
Originally published on napspan.com.
Top comments (0)