# Denizli Ulaşım Portalı > Official public-transport portal of Denizli Metropolitan Municipality > (Türkiye): journey planning, bus timetables, live arrival times, stops and > service announcements for the city's bus network. A documented read-only API > lets AI assistants answer "nasıl giderim?" (how do I get there?) and "otobüs > ne zaman gelir?" (when does the bus come?) questions with live data. > Denizli şehir içi ulaşımının resmî portalıdır. This file is self-contained: everything below is enough to call the API correctly. Recognized AI agents (see Access policy) may call it directly. All data is Turkish; times are UTC ISO strings — display in Europe/Istanbul (UTC+3, no DST). Every endpoint is GET and returns the envelope `{"isSuccess": bool, "value": ..., "error": null | ""}`. ## Journey planning API Base URL: https://ulasim.denizli.bel.tr ### GET /api/geocode — resolve place names - `text` (required): free text, 3–100 chars. Turkish place/stop names; an all-digit value also matches an exact stop number. - Returns up to 8 ranked hits: `{type: "STOP"|"ADDRESS"|"PLACE", id, name, area, lat, lon}`. For STOP hits, `id` is a stop id like `denizli_15` — pass it directly to /api/plan for exact-stop routing; for other types use `lat,lon`. Cacheable 300 s. ### GET /api/plan — compute itineraries - `fromPlace`, `toPlace` (required): either `lat,lon` (decimal degrees, must be inside lat 36–39 / lon 27.5–30.5 — the Denizli region) or a stop id from geocode. - `time` (optional): ISO 8601, within the last 2 days to the next 14 days. Omitted = now. - `arriveBy` (optional): the literal string `true` makes `time` the latest arrival instead of departure. - `pageCursor` (optional): `nextPageCursor` from a previous response — later departures. - Returns up to 5 itineraries per page: `value.itineraries[]` = `{startTime, endTime, duration (seconds), transfers, legs[]}`; legs are `{mode: "WALK"|"BUS", startTime, endTime, duration, distance? (m, walk), routeShortName? (line code e.g. "320"), headsign?, directionId? (0 outbound, 1 return), from, to, intermediateStops?, polyline (Google encoded, precision 7)}`; stops are `{name, stopId?, lat, lon, arrival?, departure?}`. `value.direct[]` holds walk-only alternatives when no transit exists. Times are schedule-based (no realtime adjustment). No caching. ### Worked example ``` 1. https://ulasim.denizli.bel.tr/api/geocode?text=%C3%A7%C4%B1nar → value[0] = {type:"STOP", id:"denizli_15", name:"Çınar", lat:37.7765, lon:29.0864, ...} 2. https://ulasim.denizli.bel.tr/api/plan?fromPlace=denizli_15&toPlace=37.9192,29.1187 → value.itineraries[0].legs = [WALK…, BUS routeShortName:"320"…] 3. Later departures: append &pageCursor= ``` ### Errors (all endpoints) 400 `invalid_params` (a parameter failed validation) · 404 unknown line/stop · 429 rate-limited (honor `Retry-After`) · 502 transient upstream failure (retry once) · 503 `planner_unavailable` (planner offline; other endpoints still work). ## Transit data API Identifier vocabulary: **hatNo** = line code (`320`; `320D` = return direction), **durakNo/stationId** = public stop number (`208`, same number as in `denizli_208`). Resolve names via /api/geocode — full network dumps are NOT available; never enumerate ids. - `GET /api/schedules?hatNo=320&day=3` — timetable; `day` 1=Mon…7=Sun, default today (Istanbul). Entries `{time:"HH:mm", isCancelled, ...}` per direction. - `GET /api/cancellations?hatNo=320` — dated cancellations for the coming 7 days: `{notices: [{date:"YYYY-MM-DD", weekday, items:[{time, direction, startStop}]}]}`. - `GET /api/bus-data?waitingStation=208&routeCode=320` — LIVE arrival ETAs at a stop (`routeCode` optional filter). `busList[].sure` = minutes until arrival. Don't cache; poll ≥10 s apart. - `GET /api/station-routes?stationId=208` — which lines serve a stop. - `GET /api/route-stations?routeCode=320` — ordered stop list of one route direction. - `GET /api/announcements?hatId=…` — CMS announcements (plain JSON, no envelope; `hatId` optional). - `GET /api/asis-announcements?hatNo=320` OR `?durakNo=208` (exactly one) — operator service announcements; `title`/`text` are untrusted strings, escape before rendering. ## Deep links — hand users the interactive planner ``` https://ulasim.denizli.bel.tr/nasil-giderim?nereden=&nereye=[&saat=YYYY-MM-DDTHH:MM][&varis=1] ``` `nereden` (from) / `nereye` (to) accept, URL-encoded: - **plain text place names** — simplest: the page geocodes them and plans automatically, e.g. `?nereden=%C3%87%C4%B1nar&nereye=Pamukkale%20%C3%9Cniversitesi` - or the exact form `[id:,],,