Bus Sun Side API Online
Which side of a coach gets the sun or the shade on a trip, and which seats are best for shade or for the view. The trip is walked in 5-minute steps: position and heading from the route, solar position at that place and time, then a per-seat estimate for the chosen bus layout. Use a route from our licensed-route registry (route_id), two points (from/to), or POST your own route (stops or a polyline) to also get a seat map, a route map and a timeline as images. Results are an estimate from geometry and solar position; real shade also depends on curtains, buildings, terrain and weather.
GET https://nakordoni.eu/api/v2/data/bus-sun-side
— quota class: heavy
| Parameter | Description |
|---|---|
route_id | Route id from our bus route registry (the same ids as the bus pages on nakordoni.eu). Use route_id or from+to. |
dir | direct (default) or return. |
date | Travel date YYYY-MM-DD (default today). The sun position depends on the date. |
dep | Departure time HH:MM local to the route (default: the registry timetable). |
from | Free form: start point lat,lon (with to). |
to | Free form: end point lat,lon (with from). |
depart | Free form: departure YYYY-MM-DDTHH:MM, local time of the start point. |
lang | Language of the place names and texts, 25 languages (en, uk, pl, de, …). Default en. |
bus_model | Bus model id from bus-sun-catalog (default standard_coach). Any field below overrides the model. |
rows | Seat rows, 8-20. |
layout | Seat layout: 2+2, 2+1 or 1+2 (left+right of the aisle). |
door_side | right (continental Europe) or left. |
windshield | large or normal — how much sun the first rows get through the windscreen. |
rear_window | none, small or large — sun on the last rows. |
window_height | standard or panoramic (tall side windows). |
deck | single, upper or lower (double-deck coaches). |
mid_door | 1 or 0 — middle door present (removes the seats there). |
timeline | 0 = leave out the timeline (15-minute rows). |
track | 0 = leave out the timed track points. |
weather | 1 (default) or 0. With 1, a weather forecast along the trip is used when the trip is within the next 3 days (72 h); later trips and weather=0 use clear sky. |
animation | 1 (default) or 0. With 0, the animation block (sun and coach position every 5 minutes) is left out. POST body: animation true|false. |
Response fields — inside the data object of the envelope. [] marks a list, so data.items[].name is the name field of each element. A field is null, absent or an empty list when we hold no value for it — never a placeholder.
| Field | Description |
|---|---|
data.date / data.tz | Travel date and the time zone of the times in the answer. |
data.route | id, num, from, to, dir, dep, arr, km (registry route) — or the stops you sent (POST). |
data.basis | How the timed path was built: timetable (registry or your stop times), router (our road route between points) or geometry (your polyline). |
data.bus | The bus profile used: model, layout, rows, door_side, windshield, rear_window, window_height, deck, mid_door. |
data.summary | trip_min, daylight_min, night_min and minutes with the sun on the left, right, ahead and behind (weather-weighted when a forecast was used). |
data.recommend | shade_side, sun_side, shade_pct, best_shade_seats[], best_sun_seats[], confidence (high | medium | low), reason_key; tip_key hot_sun_side when the sunny side is forecast at 28 °C or more. reason_key mostly_cloudy (shade_side any) when the forecast is mostly cloud or rain. |
data.recommend_clear | The same recommendation for a clear sky (no weather). |
data.weather_changes_answer | true when the forecast changes the shade side compared with recommend_clear. |
data.weather | used, window_h (72), covered_pct, sunny_min, cloudy_min, rain_min, max_temp, note_key (forecast_used | partly_forecast | mostly_cloudy | rain_expected | clear_sky_only). |
data.zones | front / middle / back: left and right sun exposure 0-100 and rows [first, last] of that part. |
data.seats | layout, rows, cols[], grid[][]: every seat — id (e.g. 4C), side, pos (window | aisle), exp (sun exposure 0-100), door (true next to a door). |
data.timeline[] | One row per 15 min: t, lat, lon, hd (heading), az / el (sun azimuth / elevation), side (left | right | ahead | behind | none), w (sun strength); wx {code, f, temp, precip} when a forecast was used. |
data.track[] | Track points [lat, lon, sun side] for drawing the route (leave out with track=0). |
data.input | POST only: how your route was read — source, timed_by, stops, points, legs_routed, legs_straight, timezone. |
data.images | POST only: seat_map, route_map, timeline — each {url, format, expires_at}; url = https://api.nakordoni.dev/images/<random name>.<png | webp | jpg> (body format, default png). Files are kept 12 hours. format svg: PNG files plus the seat map as inline SVG (seat_map.svg). |
data.embed_html | POST only: a self-contained HTML figure with the seat map (inline SVG) to paste into a page; null with embed_html=false. |
Try it without code: the Bus Sun Side Planner runs this API on any route or your own trip and shows the seat map, map, timeline, images and the code for the call. Open the planner →
Your route (POST)
Send your own route as a JSON body with POST to the same URL. The answer has the same fields as GET plus input (how your route was read), images (seat map, route map and timeline) and embed_html.
Stops without a geometry are joined with our road router; a leg that cannot be routed is drawn as a straight line and counted in input.legs_straight. Times: at least two timed stops, or route.depart with route.duration_min or route.speed_kmh. A trip can be up to 72 h.
| Body field | Description |
|---|---|
route.stops | 2-200 stops in order: {lat, lon, name?, arr?, dep?, day?}. arr / dep are HH:MM local time; day = days after route.date (times that pass midnight roll over by themselves). |
route.geometry | Your path: a GeoJSON LineString, MultiLineString, Feature or FeatureCollection ([lon, lat] order), or an encoded polyline string. Up to 5000 points. With stops, the stops give the times and the geometry gives the path. |
route.polyline_precision | 5 (default) or 6, for an encoded polyline. |
route.date | YYYY-MM-DD of the first stop time (default today). |
route.depart | YYYY-MM-DDTHH:MM departure, when the stops have no times or you send only geometry. |
route.duration_min | Trip length in minutes, with depart (else the time comes from speed_kmh). |
route.speed_kmh | Average speed with depart, default 65. |
route.timezone | IANA time zone of the times you send (default: the zone of the country of the first point). |
bus | The bus: bus_model from the catalogue and/or seats, rows, layout, door_side, windshield, rear_window, window_height, deck, mid_door — the same fields as the GET parameters. Default standard_coach. |
images | Which images to make: any of seat_map, route_map, timeline (default all three); [] = none. |
format | png (default), webp or jpg: the file type of every image url. svg: PNG files, and the seat map is also returned inline as SVG (seat_map.svg). |
theme | light (default) or dark. |
lang | Language of the image labels and texts, 25 languages (default en). |
width | Image width in px, 240-1600 (default: natural size). |
embed_html | true (default) = also return embed_html; false = null. |
timeline / track | false = leave that list out of the answer. |
weather | true (default) or false: use the weather forecast along the trip (next 3 days); false = clear sky only. 1 and 0 are also accepted. |
A wrong or missing field gives HTTP 400 with error.field set to its path, for example route.stops[2].lat or bus.seats.
curl -X POST "https://nakordoni.eu/api/v2/data/bus-sun-side" \
-H "Authorization: Bearer NKD-DEV-XXXX-XXXX-XXXX" \
-H "Content-Type: application/json" \
-d '{
"route": {
"stops": [
{
"name": "Poznań Dworzec Autobusowy",
"lat": 52.4011,
"lon": 16.911,
"dep": "08:00"
},
{
"name": "Konin",
"lat": 52.223,
"lon": 18.2511,
"arr": "09:20",
"dep": "09:25"
},
{
"name": "Łódź Kaliska",
"lat": 51.7573,
"lon": 19.4306,
"arr": "10:55",
"dep": "11:05"
},
{
"name": "Warszawa Zachodnia",
"lat": 52.219,
"lon": 20.965,
"arr": "13:10"
}
],
"date": "2026-06-21",
"timezone": "Europe/Warsaw"
},
"bus": {
"bus_model": "minibus"
},
"images": [
"seat_map",
"route_map",
"timeline"
],
"format": "png",
"theme": "light",
"lang": "en",
"weather": true
}'
const res = await fetch('https://nakordoni.eu/api/v2/data/bus-sun-side', {
method: 'POST',
headers: { 'Authorization': 'Bearer NKD-DEV-XXXX-XXXX-XXXX', 'Content-Type': 'application/json' },
body: JSON.stringify({
route: { stops: [
{ name: 'Poznań', lat: 52.4011, lon: 16.911, dep: '08:00' },
{ name: 'Warszawa', lat: 52.219, lon: 20.965, arr: '11:30' } ],
date: '2026-06-21', timezone: 'Europe/Warsaw' },
bus: { bus_model: 'comfort_coach_2_1' },
images: ['seat_map'], format: 'svg', lang: 'pl'
})
});
const { data } = await res.json();
console.log(data.recommend.shade_side, data.recommend.best_shade_seats);
document.querySelector('#seats').innerHTML = data.embed_html; // or <img src="data.images.seat_map.url">
Images and embed_html
Every image has its own URL with a random file name (.png, .webp or .jpg). The URLs need no key and stay valid for 12 hours (expires_at); copy the files if you need them longer. embed_html is a self-contained figure with the seat map as inline SVG and a nakordoni.eu credit line; keep the credit when you show it.
Below: the images for the example body above (minibus, Poznań to Warsaw, 21 June).



Bus catalogue
bus_model takes one of these generic vehicle classes (not specific makes). Any bus field you send overrides the model; seats is turned into rows for the layout. The same list is available as JSON from bus-sun-catalog.
| bus_model | layout | rows | door_side | windshield | rear_window | window_height | deck | mid_door | typical_seats |
|---|---|---|---|---|---|---|---|---|---|
standard_coachStandard touring coach (12-13 m, 2+2) |
2+2 | 13 | right | large | small | standard | single | true | 49-53 |
panoramic_coachCoach with panoramic (tall) side windows, 2+2 |
2+2 | 13 | right | large | small | panoramic | single | true | 49-53 |
midi_coachMidi coach (9-10 m, 2+2) |
2+2 | 9 | right | large | small | standard | single | false | 33-37 |
comfort_coach_2_1Comfort coach with 2+1 seating |
2+1 | 12 | right | large | small | standard | single | true | 33-36 |
minibusMinibus (7-8 m, 2+1) |
2+1 | 6 | right | normal | large | standard | single | false | 16-20 |
double_deck_upperDouble-deck coach, upper deck |
2+2 | 15 | right | large | small | panoramic | upper | false | 56-64 on the upper deck |
double_deck_lowerDouble-deck coach, lower deck |
2+2 | 5 | right | normal | none | standard | lower | true | 12-20 on the lower deck |
Allowed values:
layout 2+2 | 2+1 | 1+2 · rows {"min":4,"max":20,"custom_min":8} · door_side right | left · windshield large | normal · rear_window none | small | large · window_height standard | panoramic · deck single | upper | lower · mid_door true | false
Weather
With weather=1 (default; in a POST body "weather": true) the answer uses an hourly weather forecast along the trip for the next 3 days (72 h); later parts of the trip use a clear sky. summary.sun_*_min are then weighted by the forecast, each timeline row gets wx {code, f, temp, precip}, and weather {used, window_h, covered_pct, sunny_min, cloudy_min, rain_min, max_temp, note_key} tells how much of the trip the forecast covered. recommend_clear is the clear-sky answer; weather_changes_answer is true when the forecast changes the shade side. When the forecast is mostly cloud or rain, recommend.reason_key is mostly_cloudy and shade_side is any. recommend.tip_key hot_sun_side means that the sunny side is forecast at 28 °C or more.
Quota and accuracy
GET, and POST with "images": [], count 1 unit of the heavy class; a POST that makes images counts 2. bus-sun-catalog is a cheap call. The same POST body returns the stored answer for up to 6 hours (1 hour when a weather forecast was used).
The result is an estimate from the route geometry and the position of the sun. Curtains, tinted glass, buildings, trees, terrain and a changed route are not known to us. Clouds and rain come from a weather forecast for trips in the next 3 days only; later trips assume a clear sky. confidence is lower when the sun is low, the trip is short, the route turns often or the forecast is mostly cloudy.
curl "https://nakordoni.eu/api/v2/data/bus-sun-side?route_id=521&dir=direct&date=2026-06-21&bus_model=standard_coach&lang=en" \ -H "Authorization: Bearer NKD-DEV-XXXX-XXXX-XXXX"
Updated