← Back to all posts
Truck Parking HOS 561/2006 Austria

561/2006 Tells You When to Stop. It Doesn’t Tell You If the Bay Is Free.

July 30, 2026 · figures refreshed 10 September 2026 · 9 min read

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 occupiedAvg. free bays per site
08:00 – 14:00~39%~41
17:0052.4%31.9
19:0068.4%21.2
21:0076.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:

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:

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:

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.

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

Find the full lorry park at 14:00, not at 21:30

Live bay-level occupancy, per-hour occupancy history, and 561/2006 break planning that orders reachable parking by open spaces — in one API call. Free 14-day trial. No card.

Get Free API Key Read the Docs