PoliMI Rooms API
Get classroom schedules and room details from Politecnico di Milano. No account or API key required. All examples below use illustrative data.
Base URLhttps://api.daani.dev
GET/v1/rooms
Omit both times to get the full published schedule for a campus and date. Supply both to return only rooms that are free for the entire requested interval. Times use the campus local clock, not UTC.
| Parameter | Required | Value |
|---|---|---|
campus | Required | Campus code from the list below, e.g. MIA. |
date | Required | Calendar date in YYYY-MM-DD format. |
from | Optional pair | Start time in HH:mm format, at or after 08:00. |
to | Optional pair | End time in HH:mm format, at or before 21:00 and later than from. |
Supported campus codes
MIA- Milano Città Studi
MIB- Milano Bovisa
MIF- Milano Tortona
COE- Como
CRG- Cremona
GEM- Genova
LCF- Lecco
MNI- Mantova
PCL- Piacenza
MID- Sesto Ulteriano
curl "https://api.daani.dev/v1/rooms?campus=MIA&date=2026-10-14&from=10:00&to=12:00"{ "rooms": [ { "id": "34", "building": "Building 2", "name": "2.1.1", "occupied": [ { "from": "09:15", "to": "10:00" } ] } ]}rooms.lengthis the number of rooms returned. An empty array is a successful result, not an error.occupiedlists the room's booked intervals for the whole day, even when filtering. Interval ends are exclusive: a booking ending at 10:00 does not conflict with a search starting at 10:00.idis an optional string. If absent, room details cannot be requested. Building and room names are source-provided strings.
GET/v1/rooms/{id}
Use the numeric string id from a room schedule, not its name. The optional language query parameter accepts it or en and defaults to it.
curl "https://api.daani.dev/v1/rooms/34?language=en"{ "name": "2.1.1", "fields": { "Capacity": "60" }, "access": [ { "label": "Access", "value": "First floor" } ], "directions": [ { "label": "Entrance", "value": "Building 2" } ], "equipment": [ "Projector" ], "software": []}fields is a dictionary of source-provided labels and values. access and directions are arrays of { label, value } objects. equipment and software are string arrays. Labels and values depend on the upstream content and language; don't assume fixed field names. Arrays and dictionaries can be empty. Optional imageUrl and mapUrl are omitted when unavailable. A numeric ID is syntactically valid but not guaranteed to exist.
Usage and errors
const query = new URLSearchParams({ campus: "MIA", date: "2026-10-14", from: "10:00", to: "12:00",});const response = await fetch( `https://api.daani.dev/v1/rooms?${query}`,);const data = await response.json();if (!response.ok) { throw new Error(data.message ?? `HTTP ${response.status}`);}console.log(data.rooms);- Data endpoints return JSON. Browser requests are allowed from any origin with CORS. Use plain GET requests without credentials or custom headers.
- Each IP address may make 30 requests per minute. Cache results and avoid frequent polling. On 429, back off. Server clients can read
Retry-After; browsers cannot read that header via CORS, so wait 60 seconds. - Use the public
/v1routes onapi.daani.dev. The/apiroutes on the website are internal UI endpoints with different responses.
400- Invalid campus, date, time range, room ID, or language.
404- Unknown API route. Not an empty room search.
405- Unsupported HTTP method. Use GET to retrieve data.
429- Rate limit reached. Retry-After gives seconds to wait.
500- The server could not retrieve or process the data.
{ "message": "Choose a valid date." }Error responses are not cached. Handle HTTP status codes rather than matching message text. Also handle network failures. GET /health returns plain text ok for a running server, but does not check PoliMI availability.