{"openapi":"3.1.0","info":{"title":"havatahmin API","version":"1","summary":"7-day temperature forecast for Turkish provinces, districts, villages and neighbourhoods; free static JSON","description":"7-day temperature forecast (tmax/tmin/tmean, 90% interval) for Turkish provinces and districts (81 of 81 provinces (76 with their own station model, 5 by transfer from the nearest station: bitlis, kahramanmaras, karabuk, sirnak, sivas, which have no /v1/verification file) and 911 of 973 districts answer in the latest run). Static JSON, no server. Forecast, places and search endpoints are free; alerts and verification need an API key (Request an API key via the contact form: https://www.abso.net/iletisim-formu/ (state name, purpose and expected daily requests).) A 404 means no forecast in the latest run, too far from every station, or a misspelled slug: /v1/status.json `missing` lists them. The edge answers in this order: 400 for an unsafe path, 404 for an unknown path or slug (with or without a key), 403 for a present but unknown key (every path), 401 for a missing key on a key endpoint. Paths without the .json suffix are not JSON endpoints: /il/{il} and /api redirect (301) to their trailing-slash HTML pages. A province forecast is the point forecast at its main station; for province-wide alerts query its districts. All dates are Istanbul (UTC+3, no DST). `issued` and `valid` are calendar dates; to answer for a date D pick the day whose `valid` equals D; `lead` = `valid` - `issued` in days (lead 1 = the day after `issued`). `produced_at`, `status.time` and `next_run_expected` carry +03:00; `generated_at` (places.json, index.json) is UTC with offset. `cycle` (00Z/12Z) is the UTC hour of the ECMWF run. Rate limit: 300 requests per client IP per 5 minutes (with or without a key); above that a JSON 403 whose error starts with \"rate limit exceeded\" and carries key_request_url. Cache responses: they change at most twice a day, with no fixed schedule (see /v1/status.json). Full agent documentation: https://havatahmin.abso.net/llms-full.txt","license":{"name":"CC BY 4.0","url":"https://creativecommons.org/licenses/by/4.0/"},"contact":{"url":"https://www.abso.net/iletisim-formu/"}},"servers":[{"url":"https://havatahmin.abso.net"}],"externalDocs":{"description":"Agent documentation (Markdown); human docs in Turkish at /api/","url":"https://havatahmin.abso.net/llms-full.txt"},"tags":[{"name":"meta","description":"status, freshness and the endpoint index"},{"name":"places","description":"which places exist and their slugs"},{"name":"forecast","description":"7-day forecasts (free)"},{"name":"search","description":"resolve any place name to a forecast path and elevation offset"},{"name":"air_quality","description":"daily mean PM2.5/PM10/NO2/O3/SO2/CO at monitoring stations, D+1..D+3 (free)"},{"name":"alerts","description":"frost / heat / sudden-change flags (API key)"},{"name":"verification","description":"forecast quality vs thermometers (API key)"}],"paths":{"/v1/status.json":{"get":{"operationId":"status","tags":["meta"],"summary":"Latest run, model version, freshness (stale, age_hours, next_run_expected, missing)","description":"Read this first. `stale` = today_istanbul > `issued` + 1 day, evaluated when the file was written; the file is static, so compare now with `stale_after` (issued + 2 days, 00:00 Istanbul): at or past it, treat the run as stale even if `stale` reads false. `produced_at` is when the calculator computed the run (data time, +03:00), usually hours after the ECMWF cycle named by `issued` + `cycle`; `age_hours` = hours since `produced_at` at export; `status.time` is when the files were rendered. There is no fixed schedule: a run is published when the operator's machine runs the update, usually twice a day (the 00Z run between ~10:30 and 11:00, the 12Z run between ~20:30 and 23:00 Istanbul). `next_run_expected` is the usual earliest time of the following run, an expectation, not a promise: in the past means not published yet, so rely on `stale` and `age_hours`. `hres_latest_run` is the newest ECMWF HRES input per cycle (YYYYMMDD), not a forecast. `missing.provinces`/`missing.districts` list the slugs that 404 in this run. `provinces_with_forecast` counts provinces with their own station model; a province without one is served by transfer from the nearest station (`method` \"transfer\") and still answers at /v1/forecast/{il}.json, but is counted in `districts_with_forecast`. Use `missing` for what really 404s; index.json `coverage` has the counts as served.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"},"examples":{"live":{"summary":"the live document","value":{"time":"2026-10-10T22:54:05+03:00","model_version":"v4_20261010_1050_v4b","latest_run":"2026-10-10T12","produced_at":"2026-10-10T22:54:01+03:00","provinces_served":81,"provinces_with_forecast":76,"districts_total":973,"districts_with_forecast":916,"stations":99,"hres_latest_run":{"00":"20261010","12":"20261010"},"synop_latest_day":"2026-10-10","age_hours":0.0,"stale":false,"stale_after":"2026-10-12T00:00:00+03:00","next_run_expected":"2026-10-11T10:30:00+03:00","missing":{"provinces":[],"districts":["adana/feke","adana/saimbeyli","adana/tufanbeyli","antalya/akseki","antalya/alanya","antalya/demre","antalya/gazipasa","antalya/gundogmus","antalya/kas","balikesir/ayvalik","balikesir/burhaniye","balikesir/gomec","burdur/altinyayla","edirne/ipsala","erzincan/ilic","erzincan/kemaliye","erzurum/karacoban","eskisehir/gunyuzu","eskisehir/sivrihisar","kahramanmaras/afsin","kahramanmaras/caglayancerit","kahramanmaras/dulkadiroglu","kahramanmaras/ekinozu","kahramanmaras/elbistan","kahramanmaras/goksun","kayseri/sariz","konya/ahirli","konya/aksehir","konya/bozkir","konya/celtik","konya/cihanbeyli-district","konya/derebucak","konya/huyuk","konya/kulu","konya/seydisehir","konya/tuzlukcu","konya/yalihuyuk","konya/yunak","manisa/alasehir","mersin/anamur","mersin/aydincik","mersin/bozyazi","mersin/gulnar","mugla/fethiye","mugla/seydikemer","sanliurfa/ceylanpinar","sanliurfa/viransehir","sirnak/silopi","sivas/akincilar","sivas/altinyayla","sivas/divrigi","sivas/dogansar","sivas/golova","sivas/hafik","sivas/imranli","sivas/kangal","sivas/sarkisla","sivas/susehri","sivas/ulas","sivas/zara","van/caldiran","yozgat/akdagmadeni"]},"products":{"raw":true,"precip":"precip_v1_20261010","hourly":true,"aq":"aq_v1_20261010"}}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/latest.json":{"get":{"operationId":"latest","tags":["meta"],"summary":"Alias of /v1/status.json","description":"Byte-for-byte the same document as /v1/status.json.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"},"examples":{"live":{"summary":"the live document","value":{"time":"2026-10-10T22:54:05+03:00","model_version":"v4_20261010_1050_v4b","latest_run":"2026-10-10T12","produced_at":"2026-10-10T22:54:01+03:00","provinces_served":81,"provinces_with_forecast":76,"districts_total":973,"districts_with_forecast":916,"stations":99,"hres_latest_run":{"00":"20261010","12":"20261010"},"synop_latest_day":"2026-10-10","age_hours":0.0,"stale":false,"stale_after":"2026-10-12T00:00:00+03:00","next_run_expected":"2026-10-11T10:30:00+03:00","missing":{"provinces":[],"districts":["adana/feke","adana/saimbeyli","adana/tufanbeyli","antalya/akseki","antalya/alanya","antalya/demre","antalya/gazipasa","antalya/gundogmus","antalya/kas","balikesir/ayvalik","balikesir/burhaniye","balikesir/gomec","burdur/altinyayla","edirne/ipsala","erzincan/ilic","erzincan/kemaliye","erzurum/karacoban","eskisehir/gunyuzu","eskisehir/sivrihisar","kahramanmaras/afsin","kahramanmaras/caglayancerit","kahramanmaras/dulkadiroglu","kahramanmaras/ekinozu","kahramanmaras/elbistan","kahramanmaras/goksun","kayseri/sariz","konya/ahirli","konya/aksehir","konya/bozkir","konya/celtik","konya/cihanbeyli-district","konya/derebucak","konya/huyuk","konya/kulu","konya/seydisehir","konya/tuzlukcu","konya/yalihuyuk","konya/yunak","manisa/alasehir","mersin/anamur","mersin/aydincik","mersin/bozyazi","mersin/gulnar","mugla/fethiye","mugla/seydikemer","sanliurfa/ceylanpinar","sanliurfa/viransehir","sirnak/silopi","sivas/akincilar","sivas/altinyayla","sivas/divrigi","sivas/dogansar","sivas/golova","sivas/hafik","sivas/imranli","sivas/kangal","sivas/sarkisla","sivas/susehri","sivas/ulas","sivas/zara","van/caldiran","yozgat/akdagmadeni"]},"products":{"raw":true,"precip":"precip_v1_20261010","hourly":true,"aq":"aq_v1_20261010"}}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/index.json":{"get":{"operationId":"index","tags":["meta"],"summary":"Endpoint list, coverage, errors, limits, license and province slugs in one document","description":"Machine-readable entry point: the endpoint table, auth and rate-limit rules, error bodies, time-zone rule and every province slug.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"examples":{"live":{"summary":"the live document","value":{"name":"havatahmin api","version":"v1","self":"/index.json","latest_run":"2026-10-10T12","model_version":"v4_20261010_1050_v4b","generated_at":"2026-10-10T19:54:05+00:00","coverage":{"provinces_total":81,"provinces_answering":81,"provinces_station_model":76,"provinces_transfer":5,"provinces_transfer_slugs":["bitlis","kahramanmaras","karabuk","sirnak","sivas"],"provinces_with_verification":0,"districts_total":973,"districts_answering":911,"summary":"81 of 81 provinces (76 with their own station model, 5 by transfer from the nearest station: bitlis, kahramanmaras, karabuk, sirnak, sivas, which have no /v1/verification file) and 911 of 973 districts answer in the latest run","note":"counted from the published files of this run. Not every served place has a forecast in every run; a 404 on /v1/forecast/... means no forecast in the latest run, too far from every station, or a misspelled slug: /v1/status.json `missing` lists the exact slugs. `provinces_with_forecast` counts provinces with their own station model; a province without one is served by transfer from the nearest station (`method` \"transfer\") and still answers at /v1/forecast/{il}.json, but is counted in `districts_with_forecast`. Use `missing` for what really 404s; index.json `coverage` has the counts as served."},"freshness":"`stale` = today_istanbul > `issued` + 1 day, evaluated when the file was written; the file is static, so compare now with `stale_after` (issued + 2 days, 00:00 Istanbul): at or past it, treat the run as stale even if `stale` reads false. `produced_at` is when the calculator computed the run (data time, +03:00), usually hours after the ECMWF cycle named by `issued` + `cycle`; `age_hours` = hours since `produced_at` at export; `status.time` is when the files were rendered. There is no fixed schedule: a run is published when the operator's machine runs the update, usually twice a day (the 00Z run between ~10:30 and 11:00, the 12Z run between ~20:30 and 23:00 Istanbul). `next_run_expected` is the usual earliest time of the following run, an expectation, not a promise: in the past means not published yet, so rely on `stale` and `age_hours`. `hres_latest_run` is the newest ECMWF HRES input per cycle (YYYYMMDD), not a forecast. `missing.provinces`/`missing.districts` list the slugs that 404 in this run.","timezone":"All dates are Istanbul (UTC+3, no DST). `issued` and `valid` are calendar dates; to answer for a date D pick the day whose `valid` equals D; `lead` = `valid` - `issued` in days (lead 1 = the day after `issued`). `produced_at`, `status.time` and `next_run_expected` carry +03:00; `generated_at` (places.json, index.json) is UTC with offset. `cycle` (00Z/12Z) is the UTC hour of the ECMWF run.","province_vs_district":"a province forecast is the point forecast at its main station (verified_against.station); for province-wide alerts, query every district via /v1/districts/{il}.json","alerts":"frost: likely when tmin <= 0, possible when tmin.p05 <= 0; heat: likely when tmax >= 35, possible when tmax.p95 >= 35; sudden_change when |day-to-day change of tmean| >= 6. Thresholds are applied to the published rounded values, so 0.0 and 35.0 do trigger. For a village/neighbourhood apply them to the offset-shifted values.","products":{"raw":true,"precip":"precip_v1_20261010","hourly":true,"aq":"aq_v1_20261010","notes":{"raw":"ECMWF HRES values for the place and local day, uncorrected and unverified (the honesty label is the name): gust = day max, precip/snowfall = day accumulation (water equivalent), cloud/humidity/pressure = day mean, rh_min = day min, precip_type = most frequent ECMWF ptype of the day (none|rain|freezing rain|snow|wet snow|rain-snow mix|ice pellets). Null when the store lacks the run.","precip":"rain probability and amount for the 06-06 UTC day (09:00-09:00 Istanbul) of each lead, from the calculator's precipitation model on the HRES raw fields: pop_01/pop_1/pop_5 = P(>= 0.1 / 1 / 5 mm), mm = median amount, q90 = 90th percentile; method 'model' on a station, 'anchor' on a district (the nearest station's values, rain is local). Not the same window as tmax/tmin (calendar day).","hourly":"/v1/hourly/{path}.json: 24 local hours per lead; t = the served curve (HRES shape rescaled to our Tmin/Tmax plus a per-hour correction fitted on thermometer reports), t_raw = ECMWF HRES's own curve interpolated to the hour. Hour 0..23 Istanbul of the day `valid`.","aq":"/v1/aq/{il}.json: daily mean PM2.5, PM10, NO2, O3, SO2, CO (µg/m³) for D+1..D+3 at the province's air-quality stations, issued with the 00Z run from observations to the end of D-1; persistence = the D-1 observed mean. Stations: /v1/aq/stations.json."}},"endpoints":[{"path":"/v1/status.json","auth":"none","description":"latest run, model version, freshness (stale, age_hours, next_run_expected, missing)"},{"path":"/index.json","auth":"none","description":"endpoint list, coverage, errors, limits, license and province slugs in one document"},{"path":"/v1/places.json","auth":"none","description":"every province + district: name, slug, path, lat, lon, elev_m (~112 KB)"},{"path":"/v1/places.min.json","auth":"none","description":"compact place index: [path, name, lat, lon] rows for provinces and districts (~45 KB)"},{"path":"/v1/forecast/{il}.json","auth":"none","description":"7-day forecast for a province (point forecast at its main station), plus each anchoring station's own days"},{"path":"/v1/forecast/{il}/{ilce}.json","auth":"none","description":"7-day forecast for a district"},{"path":"/v1/hourly/{il}.json","auth":"none","description":"hourly temperature curve for a province: 24 local hours for each of the 7 days (t = corrected, t_raw = ECMWF HRES)"},{"path":"/v1/hourly/{il}/{ilce}.json","auth":"none","description":"hourly temperature curve for a district"},{"path":"/v1/aq/{il}.json","auth":"none","description":"air quality: daily mean PM2.5, PM10, NO2, O3, SO2, CO (µg/m³) for D+1..D+3 at the province's monitoring stations"},{"path":"/v1/aq/stations.json","auth":"none","description":"every air-quality station with its coordinates, district and the province file that holds its forecast"},{"path":"/v1/districts/{il}.json","auth":"none","description":"districts of a province, each with slug, path, display_name and has_forecast"},{"path":"/v1/search/{prefix}.json","auth":"none","description":"name search shard: provinces, districts and ~54,000 villages/neighbourhoods whose folded name starts with {prefix}"},{"path":"/v1/search/index.json","auth":"none","description":"search rules, lapse rates and the list of existing shard prefixes"},{"path":"/v1/alerts/{il}.json","auth":"api_key","description":"frost / heat / sudden-change flags for the week at the province's main station"},{"path":"/v1/alerts/{il}/{ilce}.json","auth":"api_key","description":"same flags for a district"},{"path":"/v1/verification/{il}.json","auth":"api_key","description":"MAE vs raw HRES per lead over the last 30 days, against the station thermometer; 404 until a run is verified or for a province without a station"},{"path":"/v1/verification/all.json","auth":"api_key","description":"same, across all served places"}],"resolve_place_name":"any province, district, village or neighbourhood: fold the name -> first 3 characters -> /v1/search/{abc}.json -> entry whose `slug` matches -> /v1/forecast/{path}.json + `offset`; coordinates: nearest district row (path with a slash) in /v1/places.min.json; full recipe in /llms-full.txt","auth":{"methods":["x-api-key header","?key= query parameter"],"on_missing_key":401,"on_invalid_key":403,"note":"the edge checks the path first: an unknown path or slug is 404 whether or not a key is sent; then a present but unknown key is 403 on every path, free ones included; then a missing key on a key endpoint is 401. 401/403 bodies carry key_request_url","how_to_get_a_key":"Request an API key via the contact form: https://www.abso.net/iletisim-formu/ (state name, purpose and expected daily requests)."},"rate_limit":{"per_ip":"300 requests per client IP per 5 minutes, with or without a key","exceeded":"HTTP 403 with the JSON body in errors.403_rate_limit until the rate drops (CloudFront cannot emit 429; no Retry-After header); cache responses, they change twice a day; fetching every place is ~1000 requests, spread them over 20 minutes","how_to_get_a_key":"Request an API key via the contact form: https://www.abso.net/iletisim-formu/ (state name, purpose and expected daily requests)."},"aliases":{"/latest.json":"same as /v1/status.json"},"errors":{"404":{"error":"not found","hint":"unknown slug, or no forecast in this run (see /v1/status.json missing); slugs: /v1/places.json","docs":"https://havatahmin.abso.net/llms-full.txt"},"400":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"},"401":{"error":"api key required: send x-api-key header or ?key=","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"},"403":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"},"403_rate_limit":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"slugs":"lowercase ASCII with single hyphens for spaces/punctuation (ankara/cankaya, sanliurfa/birecik, mugla/yesilyurt): fold a name (lowercase; ç->c ğ->g ı/İ->i ö->o ş->s ü->u, NFKD-strip â/î/û) and compare with `slug`/`path` of /v1/places.json or a search entry, never with `name` (the calculator's spelling, ASCII for provinces, mixed for districts) or `display_name` (proper Turkish, for display)","ordering":"provinces in this file and in openapi.json are alphabetical by slug; /v1/places.json is in plate-code order","license":{"name":"CC BY 4.0","url":"https://creativecommons.org/licenses/by/4.0/","attribution":"havatahmin (https://havatahmin.abso.net); place names: GeoNames (CC BY 4.0, https://www.geonames.org/)"},"openapi":"/openapi.json","llms_txt":"/llms.txt","llms_full_txt":"/llms-full.txt","docs":"/api/","sitemap":"/sitemap.xml","discovery":["/.well-known/api-catalog","/.well-known/ard.json","/.well-known/ai-catalog.json"],"provinces":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/v1/places.json":{"get":{"operationId":"places","tags":["places"],"summary":"Every province + district: name, slug, path, lat, lon, elev_m (~112 KB)","description":"Provinces in plate-code order, each with its districts. Every entry carries `path`, ready for /v1/forecast/{path}.json, and `display_name` (proper Turkish spelling, for display). `name` is the calculator's spelling (ASCII for provinces, mixed for districts): match on slugs, show display_name.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Places"},"examples":{"live":{"summary":"truncated to the first province and 2 of its districts","value":{"generated_at":"2026-10-10T19:54:05+00:00","provinces":[{"name":"Adana","display_name":"Adana","slug":"adana","lat":37.0,"lon":35.32,"elev_m":29.0,"path":"adana","districts":[{"name":"Aladağ","display_name":"Aladağ","slug":"aladag","path":"adana/aladag","lat":37.55854,"lon":35.40196,"elev_m":919.0},{"name":"Ceyhan","display_name":"Ceyhan","slug":"ceyhan","path":"adana/ceyhan","lat":37.07496,"lon":35.83629,"elev_m":24.0}]}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/v1/places.min.json":{"get":{"operationId":"placesMin","tags":["places"],"summary":"Compact place index: [path, name, lat, lon] rows for provinces and districts (~45 KB)","description":"For agents that resolve slugs or coordinates themselves: one row per province and district, `columns` names the fields. Nearest place to a coordinate = row with the smallest haversine distance.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlacesMin"},"examples":{"live":{"summary":"truncated to 3 rows","value":{"generated_at":"2026-10-10T19:54:05+00:00","columns":["path","name","lat","lon"],"note":"provinces then their districts, plate-code order; path -> /v1/forecast/{path}.json; nearest district to a coordinate = argmin haversine(lat, lon) over district entries (skip provinces: a city centre would snap to the province station)","rows":[["adana","Adana",37.0,35.32],["adana/aladag","Aladağ",37.55854,35.40196],["adana/ceyhan","Ceyhan",37.07496,35.83629]]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/v1/forecast/{il}.json":{"get":{"operationId":"forecastProvince","tags":["forecast"],"summary":"7-day forecast for a province (point forecast at its main station), plus each anchoring station's own days","description":"7 days from `issued`+1. tmax/tmin/tmean each carry `value` and the calibrated 90% interval `p05`..`p95` (°C). a province forecast is the point forecast at its main station (verified_against.station); for province-wide alerts, query every district via /v1/districts/{il}.json. All dates are Istanbul (UTC+3, no DST). `issued` and `valid` are calendar dates; to answer for a date D pick the day whose `valid` equals D; `lead` = `valid` - `issued` in days (lead 1 = the day after `issued`). `produced_at`, `status.time` and `next_run_expected` carry +03:00; `generated_at` (places.json, index.json) is UTC with offset. `cycle` (00Z/12Z) is the UTC hour of the ECMWF run.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Forecast"},"examples":{"live":{"summary":"GET /v1/forecast/adana.json, `stations` omitted","value":{"place":"Adana","display_name":"Adana","province":"Adana","province_display_name":"Adana","kind":"place","lat":37.0,"lon":35.32,"issued":"2026-10-10","cycle":"12Z","model_version":"v4_20261010_1050_v4b","produced_at":"2026-10-10T22:54:01+03:00","method":"station model","elev_diff_m":0.0,"verified_against":{"station":"17352","distance_km":5.0},"days":[{"valid":"2026-10-11","lead":1,"tmax":{"value":31.8,"p05":29.3,"p95":33.2,"official_333":32.1},"tmin":{"value":20.3,"p05":18.7,"p95":22.6,"official_333":19.7},"tmean":{"value":24.7,"p05":24.6,"p95":26.9},"raw_hres":{"tmax":29.9,"tmin":21.3,"tmean":24.9},"raw":{"gust_max_ms":9.6,"wind_ms":2.6,"wind_dir_deg":39.1,"cloud_pct":61.5,"rh_mean_pct":50.4,"rh_min_pct":34.9,"precip_mm":0.3,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":4.0,"msl_hpa":1012.8,"cape_jkg":562.4,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.4,"pop_1":0.27,"pop_5":0.14,"mm":0.1,"q90":7.7,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-12","lead":2,"tmax":{"value":26.9,"p05":25.0,"p95":29.8,"official_333":27.8},"tmin":{"value":19.5,"p05":18.3,"p95":21.8,"official_333":19.9},"tmean":{"value":23.2,"p05":22.2,"p95":24.9},"raw_hres":{"tmax":25.3,"tmin":18.7,"tmean":21.8},"raw":{"gust_max_ms":8.8,"wind_ms":1.7,"wind_dir_deg":29.1,"cloud_pct":71.3,"rh_mean_pct":72.8,"rh_min_pct":55.3,"precip_mm":2.4,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.4,"msl_hpa":1014.5,"cape_jkg":959.8,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.28,"pop_1":0.24,"pop_5":0.12,"mm":0.2,"q90":6.8,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-13","lead":3,"tmax":{"value":27.2,"p05":25.7,"p95":29.9,"official_333":28.2},"tmin":{"value":18.1,"p05":16.8,"p95":20.2,"official_333":18.4},"tmean":{"value":22.6,"p05":21.4,"p95":24.2},"raw_hres":{"tmax":26.0,"tmin":18.5,"tmean":21.7},"raw":{"gust_max_ms":4.6,"wind_ms":1.1,"wind_dir_deg":347.5,"cloud_pct":60.5,"rh_mean_pct":73.8,"rh_min_pct":49.8,"precip_mm":0.9,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.5,"msl_hpa":1016.5,"cape_jkg":982.5,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.18,"pop_1":0.15,"pop_5":0.05,"mm":0.0,"q90":3.2,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-14","lead":4,"tmax":{"value":25.2,"p05":22.9,"p95":29.2,"official_333":26.3},"tmin":{"value":19.0,"p05":16.9,"p95":21.0,"official_333":20.2},"tmean":{"value":22.6,"p05":20.5,"p95":24.6},"raw_hres":{"tmax":25.7,"tmin":20.0,"tmean":22.2},"raw":{"gust_max_ms":9.7,"wind_ms":2.8,"wind_dir_deg":9.0,"cloud_pct":69.1,"rh_mean_pct":68.7,"rh_min_pct":52.1,"precip_mm":0.3,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":2.4,"msl_hpa":1014.1,"cape_jkg":617.0,"precip_type":"none","precip_type_code":0},"precip":{"pop_01":0.52,"pop_1":0.41,"pop_5":0.17,"mm":1.2,"q90":12.0,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-15","lead":5,"tmax":{"value":22.8,"p05":19.4,"p95":26.8,"official_333":23.8},"tmin":{"value":16.4,"p05":14.6,"p95":18.6,"official_333":16.8},"tmean":{"value":19.2,"p05":17.2,"p95":21.5},"raw_hres":{"tmax":22.7,"tmin":16.9,"tmean":19.2},"raw":{"gust_max_ms":8.7,"wind_ms":1.7,"wind_dir_deg":82.1,"cloud_pct":51.2,"rh_mean_pct":80.8,"rh_min_pct":67.3,"precip_mm":9.7,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.1,"msl_hpa":1012.7,"cape_jkg":1053.5,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.61,"pop_1":0.47,"pop_5":0.23,"mm":1.4,"q90":14.7,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-16","lead":6,"tmax":{"value":23.7,"p05":20.4,"p95":27.7,"official_333":24.9},"tmin":{"value":16.1,"p05":14.1,"p95":18.3,"official_333":16.0},"tmean":{"value":19.7,"p05":18.0,"p95":22.4},"raw_hres":{"tmax":20.8,"tmin":16.3,"tmean":18.2},"raw":{"gust_max_ms":8.1,"wind_ms":2.1,"wind_dir_deg":28.8,"cloud_pct":75.4,"rh_mean_pct":90.0,"rh_min_pct":83.4,"precip_mm":25.9,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":2.6,"msl_hpa":1012.2,"cape_jkg":375.5,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.69,"pop_1":0.64,"pop_5":0.58,"mm":7.7,"q90":28.9,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-17","lead":7,"tmax":{"value":24.7,"p05":20.9,"p95":28.6,"official_333":25.9},"tmin":{"value":16.2,"p05":14.0,"p95":18.9,"official_333":16.1},"tmean":{"value":20.1,"p05":18.1,"p95":22.4},"raw_hres":{"tmax":23.2,"tmin":16.3,"tmean":19.0},"raw":{"gust_max_ms":6.8,"wind_ms":2.3,"wind_dir_deg":60.3,"cloud_pct":42.4,"rh_mean_pct":85.9,"rh_min_pct":69.2,"precip_mm":18.5,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.6,"msl_hpa":1014.0,"cape_jkg":581.2,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.25,"pop_1":0.15,"pop_5":0.08,"mm":0.0,"q90":5.4,"method":"model","window":"06-06 UTC (09:00-09:00 Istanbul)"}}],"precip_model_version":"precip_v1_20261010","products":{"raw":"ECMWF HRES values for the place and local day, uncorrected and unverified (the honesty label is the name): gust = day max, precip/snowfall = day accumulation (water equivalent), cloud/humidity/pressure = day mean, rh_min = day min, precip_type = most frequent ECMWF ptype of the day (none|rain|freezing rain|snow|wet snow|rain-snow mix|ice pellets). Null when the store lacks the run.","precip":"rain probability and amount for the 06-06 UTC day (09:00-09:00 Istanbul) of each lead, from the calculator's precipitation model on the HRES raw fields: pop_01/pop_1/pop_5 = P(>= 0.1 / 1 / 5 mm), mm = median amount, q90 = 90th percentile; method 'model' on a station, 'anchor' on a district (the nearest station's values, rain is local). Not the same window as tmax/tmin (calendar day).","hourly":"/v1/hourly/adana.json"}}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no forecast in the latest run (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"}]}},"/v1/forecast/{il}/{ilce}.json":{"get":{"operationId":"forecastDistrict","tags":["forecast"],"summary":"7-day forecast for a district","description":"Same shape as the province forecast without `stations`; `method` is transfer or transfer+lapse from the anchor station in `verified_against`. For a village or neighbourhood, add the search entry's `offset` to every value/p05/p95. All dates are Istanbul (UTC+3, no DST). `issued` and `valid` are calendar dates; to answer for a date D pick the day whose `valid` equals D; `lead` = `valid` - `issued` in days (lead 1 = the day after `issued`). `produced_at`, `status.time` and `next_run_expected` carry +03:00; `generated_at` (places.json, index.json) is UTC with offset. `cycle` (00Z/12Z) is the UTC hour of the ECMWF run.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Forecast"},"examples":{"live":{"summary":"GET /v1/forecast/adana/aladag.json","value":{"place":"Aladağ","display_name":"Aladağ","province":"Adana","province_display_name":"Adana","kind":"district","lat":37.55854,"lon":35.40196,"issued":"2026-10-10","cycle":"12Z","model_version":"v4_20261010_1050_v4b","produced_at":"2026-10-10T22:54:01+03:00","method":"transfer","elev_diff_m":0.0,"verified_against":{"station":"17350","distance_km":62.1},"days":[{"valid":"2026-10-11","lead":1,"tmax":{"value":27.6,"p05":25.4,"p95":29.2,"official_333":28.0},"tmin":{"value":11.4,"p05":9.5,"p95":14.5,"official_333":11.5},"tmean":{"value":19.3,"p05":18.5,"p95":21.2},"raw_hres":{"tmax":25.0,"tmin":12.4,"tmean":18.5},"raw":{"gust_max_ms":8.4,"wind_ms":2.1,"wind_dir_deg":335.6,"cloud_pct":48.8,"rh_mean_pct":58.7,"rh_min_pct":39.8,"precip_mm":4.0,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":4.4,"msl_hpa":1015.0,"cape_jkg":303.0,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.41,"pop_1":0.27,"pop_5":0.14,"mm":0.1,"q90":7.8,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-12","lead":2,"tmax":{"value":24.0,"p05":21.7,"p95":26.7,"official_333":24.7},"tmin":{"value":14.8,"p05":12.6,"p95":17.4,"official_333":15.3},"tmean":{"value":18.5,"p05":17.1,"p95":20.3},"raw_hres":{"tmax":21.8,"tmin":13.8,"tmean":16.8},"raw":{"gust_max_ms":8.1,"wind_ms":1.4,"wind_dir_deg":340.8,"cloud_pct":62.3,"rh_mean_pct":82.9,"rh_min_pct":57.9,"precip_mm":6.6,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.7,"msl_hpa":1016.5,"cape_jkg":567.0,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.3,"pop_1":0.23,"pop_5":0.12,"mm":0.2,"q90":7.0,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-13","lead":3,"tmax":{"value":23.4,"p05":21.7,"p95":25.9,"official_333":24.2},"tmin":{"value":12.7,"p05":10.7,"p95":15.1,"official_333":13.0},"tmean":{"value":17.9,"p05":16.5,"p95":19.7},"raw_hres":{"tmax":21.2,"tmin":12.4,"tmean":16.3},"raw":{"gust_max_ms":6.6,"wind_ms":1.8,"wind_dir_deg":320.6,"cloud_pct":51.4,"rh_mean_pct":82.5,"rh_min_pct":60.7,"precip_mm":2.7,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.9,"msl_hpa":1017.8,"cape_jkg":965.5,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.2,"pop_1":0.15,"pop_5":0.05,"mm":0.0,"q90":3.2,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-14","lead":4,"tmax":{"value":21.4,"p05":18.6,"p95":25.4,"official_333":22.3},"tmin":{"value":13.8,"p05":11.0,"p95":16.1,"official_333":14.8},"tmean":{"value":18.0,"p05":15.8,"p95":20.1},"raw_hres":{"tmax":20.3,"tmin":14.0,"tmean":16.8},"raw":{"gust_max_ms":7.2,"wind_ms":1.9,"wind_dir_deg":358.4,"cloud_pct":80.1,"rh_mean_pct":78.0,"rh_min_pct":65.8,"precip_mm":1.4,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":2.2,"msl_hpa":1016.0,"cape_jkg":483.8,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.52,"pop_1":0.4,"pop_5":0.2,"mm":1.2,"q90":12.3,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-15","lead":5,"tmax":{"value":17.3,"p05":14.2,"p95":21.5,"official_333":18.2},"tmin":{"value":12.4,"p05":9.6,"p95":14.8,"official_333":12.7},"tmean":{"value":14.6,"p05":12.6,"p95":17.3},"raw_hres":{"tmax":16.8,"tmin":12.5,"tmean":14.4},"raw":{"gust_max_ms":7.6,"wind_ms":0.7,"wind_dir_deg":3.2,"cloud_pct":68.9,"rh_mean_pct":90.4,"rh_min_pct":81.9,"precip_mm":17.1,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":2.9,"msl_hpa":1014.0,"cape_jkg":711.5,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.61,"pop_1":0.47,"pop_5":0.24,"mm":1.4,"q90":14.6,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-16","lead":6,"tmax":{"value":22.6,"p05":19.3,"p95":26.2,"official_333":23.4},"tmin":{"value":11.2,"p05":8.7,"p95":13.8,"official_333":11.2},"tmean":{"value":16.3,"p05":14.4,"p95":18.7},"raw_hres":{"tmax":19.7,"tmin":10.9,"tmean":14.6},"raw":{"gust_max_ms":6.5,"wind_ms":1.0,"wind_dir_deg":329.9,"cloud_pct":78.5,"rh_mean_pct":85.4,"rh_min_pct":72.6,"precip_mm":9.8,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":2.8,"msl_hpa":1013.1,"cape_jkg":232.5,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.69,"pop_1":0.64,"pop_5":0.57,"mm":7.4,"q90":30.4,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}},{"valid":"2026-10-17","lead":7,"tmax":{"value":20.8,"p05":16.9,"p95":24.3,"official_333":21.7},"tmin":{"value":12.7,"p05":10.2,"p95":15.7,"official_333":12.6},"tmean":{"value":16.6,"p05":14.2,"p95":18.9},"raw_hres":{"tmax":18.3,"tmin":12.6,"tmean":14.9},"raw":{"gust_max_ms":6.6,"wind_ms":1.3,"wind_dir_deg":75.6,"cloud_pct":65.0,"rh_mean_pct":87.2,"rh_min_pct":68.2,"precip_mm":9.5,"snowfall_mm":0.0,"snow_depth_cm":0.0,"solar_kwh_m2":3.5,"msl_hpa":1015.0,"cape_jkg":209.8,"precip_type":"rain","precip_type_code":1},"precip":{"pop_01":0.26,"pop_1":0.15,"pop_5":0.08,"mm":0.0,"q90":6.1,"method":"anchor","window":"06-06 UTC (09:00-09:00 Istanbul)"}}],"precip_model_version":"precip_v1_20261010","products":{"raw":"ECMWF HRES values for the place and local day, uncorrected and unverified (the honesty label is the name): gust = day max, precip/snowfall = day accumulation (water equivalent), cloud/humidity/pressure = day mean, rh_min = day min, precip_type = most frequent ECMWF ptype of the day (none|rain|freezing rain|snow|wet snow|rain-snow mix|ice pellets). Null when the store lacks the run.","precip":"rain probability and amount for the 06-06 UTC day (09:00-09:00 Istanbul) of each lead, from the calculator's precipitation model on the HRES raw fields: pop_01/pop_1/pop_5 = P(>= 0.1 / 1 / 5 mm), mm = median amount, q90 = 90th percentile; method 'model' on a station, 'anchor' on a district (the nearest station's values, rain is local). Not the same window as tmax/tmin (calendar day).","hourly":"/v1/hourly/adana/aladag.json"}}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"too far from every station, no forecast in the latest run, or a misspelled slug (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"},{"name":"ilce","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]+$"},"description":"district slug; enumerate valid values from /v1/districts/{il}.json (`slug`) or use `path` from /v1/places.json"}]}},"/v1/hourly/{il}.json":{"get":{"operationId":"hourlyProvince","tags":["forecast"],"summary":"Hourly temperature curve for a province: 24 local hours for each of the 7 days (t = corrected, t_raw = ECMWF HRES)","description":"/v1/hourly/{path}.json: 24 local hours per lead; t = the served curve (HRES shape rescaled to our Tmin/Tmax plus a per-hour correction fitted on thermometer reports), t_raw = ECMWF HRES's own curve interpolated to the hour. Hour 0..23 Istanbul of the day `valid`. Same place and rows as /v1/forecast/{il}.json; absent (404) when the run has no hourly table (status.products.hourly false). All dates are Istanbul (UTC+3, no DST). `issued` and `valid` are calendar dates; to answer for a date D pick the day whose `valid` equals D; `lead` = `valid` - `issued` in days (lead 1 = the day after `issued`). `produced_at`, `status.time` and `next_run_expected` carry +03:00; `generated_at` (places.json, index.json) is UTC with offset. `cycle` (00Z/12Z) is the UTC hour of the ECMWF run.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hourly"},"examples":{"live":{"summary":"GET /v1/hourly/adana.json, day 1 of 7","value":{"place":"Adana","display_name":"Adana","province":"Adana","province_display_name":"Adana","kind":"place","lat":37.0,"lon":35.32,"issued":"2026-10-10","cycle":"12Z","model_version":"v4_20261010_1050_v4b","produced_at":"2026-10-10T22:54:01+03:00","method":"station model","note":"/v1/hourly/{path}.json: 24 local hours per lead; t = the served curve (HRES shape rescaled to our Tmin/Tmax plus a per-hour correction fitted on thermometer reports), t_raw = ECMWF HRES's own curve interpolated to the hour. Hour 0..23 Istanbul of the day `valid`.","forecast":"/v1/forecast/adana.json","days":[{"valid":"2026-10-11","lead":1,"t":[22.4,22.1,21.9,21.8,21.5,21.2,21.0,21.1,22.7,24.9,26.6,28.5,30.1,30.9,31.3,31.5,30.7,29.6,28.0,26.5,25.1,24.1,22.5,21.0],"t_raw":[22.0,22.0,21.9,21.8,21.6,21.5,21.3,22.5,23.6,24.8,26.3,27.8,29.3,29.5,29.7,29.9,28.9,27.8,26.7,25.6,24.5,23.4,22.3,21.1]},{"...":"6 more days"}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no forecast in the latest run (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"}]}},"/v1/hourly/{il}/{ilce}.json":{"get":{"operationId":"hourlyDistrict","tags":["forecast"],"summary":"Hourly temperature curve for a district","description":"Same shape as the province file, for the district's own rows. For a village or neighbourhood add the search entry's `offset.tmean` to every hour (a daily-mean shift; the curve's shape is the district's).","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hourly"},"examples":{"live":{"summary":"GET /v1/hourly/adana/aladag.json, day 1 of 7","value":{"place":"Aladağ","display_name":"Aladağ","province":"Adana","province_display_name":"Adana","kind":"district","lat":37.55854,"lon":35.40196,"issued":"2026-10-10","cycle":"12Z","model_version":"v4_20261010_1050_v4b","produced_at":"2026-10-10T22:54:01+03:00","method":"transfer","note":"/v1/hourly/{path}.json: 24 local hours per lead; t = the served curve (HRES shape rescaled to our Tmin/Tmax plus a per-hour correction fitted on thermometer reports), t_raw = ECMWF HRES's own curve interpolated to the hour. Hour 0..23 Istanbul of the day `valid`.","forecast":"/v1/forecast/adana/aladag.json","days":[{"valid":"2026-10-11","lead":1,"t":[13.4,13.0,12.6,12.3,12.1,11.9,11.8,14.5,18.7,23.6,24.5,25.6,26.5,27.1,27.4,27.3,26.2,24.8,22.9,20.8,18.9,17.3,16.6,16.0],"t_raw":[13.3,13.1,12.9,12.7,12.6,12.5,12.4,15.6,18.8,22.1,23.0,23.9,24.8,24.9,24.9,25.0,23.7,22.4,21.1,19.5,18.0,16.4,15.9,15.4]},{"...":"6 more days"}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no forecast for this district in the latest run (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"},{"name":"ilce","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]+$"},"description":"district slug; enumerate valid values from /v1/districts/{il}.json (`slug`) or use `path` from /v1/places.json"}]}},"/v1/aq/{il}.json":{"get":{"operationId":"aqProvince","tags":["air_quality"],"summary":"Air quality: daily mean PM2.5, PM10, NO2, O3, SO2, CO (µg/m³) for D+1..D+3 at the province's monitoring stations","description":"/v1/aq/{il}.json: daily mean PM2.5, PM10, NO2, O3, SO2, CO (µg/m³) for D+1..D+3 at the province's air-quality stations, issued with the 00Z run from observations to the end of D-1; persistence = the D-1 observed mean. Stations: /v1/aq/stations.json. Only provinces with a station have a file (404 otherwise; the list is /v1/aq/stations.json). Issued once a day with the 00Z run; status.products.aq names the bundle, null when the day has none.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Aq"},"examples":{"live":{"summary":"GET /v1/aq/adana.json, 1 of 8 stations","value":{"province":"Adana","display_name":"Adana","slug":"adana","issued":"2026-10-10","aq_model_version":"aq_v1_20261010","units":"µg/m³","pollutants":["pm25","pm10","no2","o3","so2","co"],"leads":[1,2,3],"note":"/v1/aq/{il}.json: daily mean PM2.5, PM10, NO2, O3, SO2, CO (µg/m³) for D+1..D+3 at the province's air-quality stations, issued with the 00Z run from observations to the end of D-1; persistence = the D-1 observed mean. Stations: /v1/aq/stations.json.","stations":[{"station":"468478b7-ace5-4bd3-b89a-a9c1c2e53080","name":"105","lat":37.18635,"lon":35.26203,"province":"Adana","district":"Karaisalı","days":[{"valid":"2026-10-11","lead":1,"pm25":18.1,"persistence":{"pm25":null,"pm10":23.1,"no2":null,"o3":73.2,"so2":6.9,"co":null},"pm10":23.5,"no2":21.9,"o3":63.2,"so2":7.1,"co":510.6},{"valid":"2026-10-12","lead":2,"pm25":15.9,"persistence":{"pm25":null,"pm10":23.1,"no2":null,"o3":73.2,"so2":6.9,"co":null},"pm10":19.8,"no2":17.6,"o3":55.8,"so2":6.6,"co":487.5},{"valid":"2026-10-13","lead":3,"pm25":13.3,"persistence":{"pm25":null,"pm10":23.1,"no2":null,"o3":73.2,"so2":6.9,"co":null},"pm10":16.4,"no2":18.1,"o3":50.2,"so2":6.3,"co":497.6}]}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no air-quality station in this province, or no air-quality forecast today (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"}]}},"/v1/aq/stations.json":{"get":{"operationId":"aqStations","tags":["air_quality"],"summary":"Every air-quality station with its coordinates, district and the province file that holds its forecast","description":"The station list of the current air-quality forecast; `file` is the /v1/aq/{il}.json to fetch. Stations are placed by their coordinates in the calculator's district polygons.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AqStations"},"examples":{"live":{"summary":"GET /v1/aq/stations.json, 3 of 347 stations","value":{"issued":"2026-10-10","aq_model_version":"aq_v1_20261010","units":"µg/m³","pollutants":["pm25","pm10","no2","o3","so2","co"],"leads":[1,2,3],"count":347,"stations":[{"station":"468478b7-ace5-4bd3-b89a-a9c1c2e53080","name":"105","lat":37.18635,"lon":35.26203,"district":"Karaisalı","province":"Adana","path":"adana","file":"/v1/aq/adana.json"},{"station":"0ed2ff0e-9900-4e7b-ba64-c40e820104b2","name":"20","lat":36.99192,"lon":35.32605,"district":"Seyhan","province":"Adana","path":"adana","file":"/v1/aq/adana.json"},{"station":"9a381f61-657b-42ea-be87-ae7216ae953a","name":"225","lat":37.04002,"lon":35.26998,"district":"Çukurova","province":"Adana","path":"adana","file":"/v1/aq/adana.json"}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/v1/districts/{il}.json":{"get":{"operationId":"districts","tags":["places"],"summary":"Districts of a province, each with slug, path, display_name and has_forecast","description":"Lists every district of the province; `has_forecast` false means /v1/forecast/{path}.json answers 404 in this run.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Districts"},"examples":{"live":{"summary":"GET /v1/districts/adana.json, truncated to 3 districts","value":{"province":"Adana","districts":[{"name":"Aladağ","lat":37.55854,"lon":35.40196,"elev_m":919.0,"has_forecast":true,"slug":"aladag","path":"adana/aladag","display_name":"Aladağ"},{"name":"Ceyhan","lat":37.07496,"lon":35.83629,"elev_m":24.0,"has_forecast":true,"slug":"ceyhan","path":"adana/ceyhan","display_name":"Ceyhan"},{"name":"Feke","lat":37.82405,"lon":35.91826,"elev_m":859.0,"has_forecast":false,"slug":"feke","path":"adana/feke","display_name":"Feke"}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"unknown province (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"}]}},"/v1/search/{prefix}.json":{"get":{"operationId":"search","tags":["search"],"summary":"Name search shard: provinces, districts and ~54,000 villages/neighbourhoods whose folded name starts with {prefix}","description":"Fold the name (lowercase; ç->c ğ->g ı/İ->i ö->o ş->s ü->u; NFKD-strip other diacritics such as â/î/û; keep a-z0-9), take the first 3 characters (2 if that is all there is), GET this shard and pick the entry whose `slug` matches the folded name with spaces as hyphens; several entries can share a slug, separate them by `district`/`province`. Then GET /v1/forecast/{path}.json and add `offset.tmax/tmin/tmean` to value, p05 and p95 of every day. Entries are ordered provinces, districts, then settlements by GeoNames rank and population.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchShard"},"examples":{"live":{"summary":"GET /v1/search/yas.json, 2 of the entries","value":{"prefix":"yas","entries":[{"name":"Yaşamkent","kind":"neighbourhood","district":"Çankaya","province":"Ankara","path":"ankara/cankaya","slug":"yasamkent","lat":39.86139,"lon":32.65889,"elev_m":1100.0,"elev_diff_m":1,"offset":{"tmax":0.0,"tmin":0.0,"tmean":0.0},"has_forecast":true},{"name":"Yaşlıkavak","kind":"settlement","district":"Çatak","province":"Van","path":"van/catak","slug":"yaslikavak","lat":37.96667,"lon":42.86667,"elev_m":2678.0,"elev_diff_m":1171,"offset":{"tmax":-7.6,"tmin":-5.3,"tmean":-7.0},"has_forecast":true}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no place name starts with these characters (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"prefix","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9]{2,3}$"},"description":"first 3 characters of the folded name (2 when the folded name has only 2); the existing values are listed in /v1/search/index.json `prefixes`"}]}},"/v1/search/index.json":{"get":{"operationId":"searchIndex","tags":["search"],"summary":"Search rules, lapse rates and the list of existing shard prefixes","description":"How the shards are built, the elevation-offset formula and every prefix that has a shard.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"examples":{"live":{"summary":"prefixes truncated to 5","value":{"how_to":"fold the query (lowercase; ç->c, ğ->g, ı/i/İ->i, ö->o, ş->s, ü->u; NFKD-strip other diacritics such as â/î/û; drop non-alphanumerics), take its first 3 characters (2 if the folded name has only 2), GET /v1/search/<those characters>.json, match entries by `slug` (folded name, spaces as hyphens); then GET /v1/forecast/{path}.json and add `offset[t]` to value, p05 and p95 of tmax/tmin/tmean on every day","offset":"district forecast shifted to the place's elevation: -lapse * clip(elev_m - district elev, +-1500 m) / 100; lapse per 100 m: {'tmax': 0.65, 'tmin': 0.45, 'tmean': 0.6}. Same rule as the calculator's ?q= search. Results may differ from it by 0.1 C (rounding)","ordering":"provinces, then districts, then settlements by GeoNames rank and population","entries":55090,"prefixes":["100","14k","aba","abb","abd","..."],"source":"settlements and neighbourhoods: GeoNames (CC BY 4.0, https://www.geonames.org/)"}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}}}}},"/v1/alerts/{il}.json":{"get":{"operationId":"alertsProvince","tags":["alerts"],"summary":"Frost / heat / sudden-change flags for the week at the province's main station","description":"Needs an API key. Flags derived from the province forecast: frost: likely when tmin <= 0, possible when tmin.p05 <= 0; heat: likely when tmax >= 35, possible when tmax.p95 >= 35; sudden_change when |day-to-day change of tmean| >= 6. Thresholds are applied to the published rounded values, so 0.0 and 35.0 do trigger. For a village/neighbourhood apply them to the offset-shifted values. For province-wide coverage query every district.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"},"examples":{"live":{"summary":"GET /v1/alerts/agri/diyadin.json","value":{"place":"Diyadin","display_name":"Diyadin","province":"Agri","province_display_name":"Ağrı","kind":"district","lat":39.5488,"lon":43.6749,"issued":"2026-10-10","cycle":"12Z","model_version":"v4_20261010_1050_v4b","produced_at":"2026-10-10T22:54:01+03:00","method":"transfer","elev_diff_m":0.0,"verified_against":{"station":"17100","distance_km":53.0},"alerts":[{"valid":"2026-10-11","type":"frost","level":"possible","tmin_p05":-0.8}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"401":{"description":"missing key (Error body with key_request_url)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no forecast in the latest run (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"}],"security":[{"apiKey":[]},{"apiKeyQuery":[]}]}},"/v1/alerts/{il}/{ilce}.json":{"get":{"operationId":"alertsDistrict","tags":["alerts"],"summary":"Same flags for a district","description":"Needs an API key. Same rules as the province alerts, applied to the district forecast.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"},"examples":{"live":{"summary":"GET /v1/alerts/agri/diyadin.json","value":{"place":"Diyadin","display_name":"Diyadin","province":"Agri","province_display_name":"Ağrı","kind":"district","lat":39.5488,"lon":43.6749,"issued":"2026-10-10","cycle":"12Z","model_version":"v4_20261010_1050_v4b","produced_at":"2026-10-10T22:54:01+03:00","method":"transfer","elev_diff_m":0.0,"verified_against":{"station":"17100","distance_km":53.0},"alerts":[{"valid":"2026-10-11","type":"frost","level":"possible","tmin_p05":-0.8}]}}}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"401":{"description":"missing key (Error body with key_request_url)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no forecast for this district in the latest run (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"},{"name":"ilce","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]+$"},"description":"district slug; enumerate valid values from /v1/districts/{il}.json (`slug`) or use `path` from /v1/places.json"}],"security":[{"apiKey":[]},{"apiKeyQuery":[]}]}},"/v1/verification/{il}.json":{"get":{"operationId":"verification","tags":["verification"],"summary":"MAE vs raw HRES per lead over the last 30 days, against the station thermometer; 404 until a run is verified or for a province without a station","description":"Needs an API key. Per variable and lead: mae, mae_raw_hres, bias, coverage90 (share of truths inside p05..p95) and n, over the last 30 days. Provinces served by transfer (no station of their own) have no verification file; index.json coverage.provinces_transfer_slugs lists them.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"401":{"description":"missing key (Error body with key_request_url)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no verified forecast yet, or a province without its own station (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"il","in":"path","required":true,"schema":{"type":"string","enum":["adana","adiyaman","afyonkarahisar","agri","aksaray","amasya","ankara","antalya","ardahan","artvin","aydin","balikesir","bartin","batman","bayburt","bilecik","bingol","bitlis","bolu","burdur","bursa","canakkale","cankiri","corum","denizli","diyarbakir","duzce","edirne","elazig","erzincan","erzurum","eskisehir","gaziantep","giresun","gumushane","hakkari","hatay","igdir","isparta","istanbul","izmir","kahramanmaras","karabuk","karaman","kars","kastamonu","kayseri","kilis","kirikkale","kirklareli","kirsehir","kocaeli","konya","kutahya","malatya","manisa","mardin","mersin","mugla","mus","nevsehir","nigde","ordu","osmaniye","rize","sakarya","samsun","sanliurfa","siirt","sinop","sirnak","sivas","tekirdag","tokat","trabzon","tunceli","usak","van","yalova","yozgat","zonguldak"]},"description":"province slug (lowercase ASCII)"}],"security":[{"apiKey":[]},{"apiKeyQuery":[]}]}},"/v1/verification/all.json":{"get":{"operationId":"verificationAll","tags":["verification"],"summary":"Same, across all served places","description":"Needs an API key. The verification summary pooled over every served place.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"400":{"description":"path hygiene: `..`, `//`, `\\` or percent-encoded `.`/`/`/`\\` in the path are refused at the edge before any lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_path":{"value":{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"401":{"description":"missing key (Error body with key_request_url)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"invalid api key (Error body with key_request_url; a present but unknown key is refused on every path, free ones included), or rate limit exceeded (RateLimit body, `error` starts with \"rate limit exceeded\"; 300 requests per IP per 5 minutes, CloudFront cannot emit 429)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/RateLimit"}]},"examples":{"invalid_key":{"value":{"error":"invalid api key","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}},"rate_limit":{"value":{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}}}}}},"404":{"description":"no verified forecast yet (Error body with hint)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"apiKey":[]},{"apiKeyQuery":[]}]}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key"},"apiKeyQuery":{"type":"apiKey","in":"query","name":"key"}},"schemas":{"Error":{"type":"object","required":["error","docs"],"properties":{"error":{"type":"string"},"hint":{"type":"string","description":"404 only"},"key_request_url":{"type":"string","format":"uri","description":"401 and 403 only: where to ask for a free key"},"docs":{"type":"string","format":"uri"}},"examples":[{"error":"not found","hint":"unknown slug, or no forecast in this run (see /v1/status.json missing); slugs: /v1/places.json","docs":"https://havatahmin.abso.net/llms-full.txt"},{"error":"api key required: send x-api-key header or ?key=","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"},{"error":"invalid path","docs":"https://havatahmin.abso.net/llms-full.txt"}]},"RateLimit":{"type":"object","required":["error","key_request_url"],"description":"WAF rate-limit block, served as 403 (CloudFront cannot emit 429; no Retry-After header): tell it apart from the key error by `error` starting with \"rate limit exceeded\"","properties":{"error":{"type":"string","pattern":"^rate limit exceeded"},"fix":{"type":"string"},"key_request_url":{"type":"string","format":"uri"},"docs":{"type":"string","format":"uri"}},"examples":[{"error":"rate limit exceeded: more than 300 requests from this IP in 5 minutes (or a method other than GET/HEAD/OPTIONS: the API is read-only)","fix":"cache responses (they change twice a day) and spread requests out; building something on this API? request a free API key via key_request_url and tell us your expected volume","key_request_url":"https://www.abso.net/iletisim-formu/","docs":"https://havatahmin.abso.net/llms-full.txt"}]},"DayValue":{"type":"object","properties":{"value":{"type":"number"},"p05":{"type":"number"},"p95":{"type":"number"}},"required":["value","p05","p95"],"description":"°C; p05 <= value <= p95 (calibrated 90% interval)"},"RawFields":{"type":"object","description":"ECMWF HRES values for the place and local day, uncorrected and unverified (the honesty label is the name): gust = day max, precip/snowfall = day accumulation (water equivalent), cloud/humidity/pressure = day mean, rh_min = day min, precip_type = most frequent ECMWF ptype of the day (none|rain|freezing rain|snow|wet snow|rain-snow mix|ice pellets). Null when the store lacks the run.","properties":{"gust_max_ms":{"type":["number","null"],"description":"m/s, day max"},"wind_ms":{"type":["number","null"],"description":"m/s, day mean"},"wind_dir_deg":{"type":["number","null"],"description":"degrees, blowing from"},"cloud_pct":{"type":["number","null"],"description":"%"},"rh_mean_pct":{"type":["number","null"],"description":"%"},"rh_min_pct":{"type":["number","null"],"description":"%"},"precip_mm":{"type":["number","null"],"description":"mm, day accumulation"},"snowfall_mm":{"type":["number","null"],"description":"mm water equivalent"},"snow_depth_cm":{"type":["number","null"],"description":"cm"},"solar_kwh_m2":{"type":["number","null"],"description":"kWh/m², day total"},"msl_hpa":{"type":["number","null"],"description":"hPa, day mean"},"cape_jkg":{"type":["number","null"],"description":"J/kg, day max"},"precip_type":{"type":["string","null"],"enum":["none","rain","freezing rain","snow","wet snow","rain-snow mix","ice pellets",null]},"precip_type_code":{"type":["integer","null"],"description":"ECMWF ptype code"}}},"Precip":{"type":"object","description":"rain probability and amount for the 06-06 UTC day (09:00-09:00 Istanbul) of each lead, from the calculator's precipitation model on the HRES raw fields: pop_01/pop_1/pop_5 = P(>= 0.1 / 1 / 5 mm), mm = median amount, q90 = 90th percentile; method 'model' on a station, 'anchor' on a district (the nearest station's values, rain is local). Not the same window as tmax/tmin (calendar day).","required":["pop_01","pop_1","pop_5","mm","q90","method","window"],"properties":{"pop_01":{"type":["number","null"],"minimum":0,"maximum":1,"description":"P(>= 0.1 mm)"},"pop_1":{"type":["number","null"],"minimum":0,"maximum":1,"description":"P(>= 1 mm)"},"pop_5":{"type":["number","null"],"minimum":0,"maximum":1,"description":"P(>= 5 mm)"},"mm":{"type":["number","null"],"description":"median amount, mm"},"q90":{"type":["number","null"],"description":"90th percentile, mm"},"method":{"type":["string","null"],"enum":["model","anchor",null],"description":"model on a station, anchor on a district (nearest station's values)"},"window":{"type":"string","const":"06-06 UTC (09:00-09:00 Istanbul)"}}},"Day":{"type":"object","properties":{"valid":{"type":"string","format":"date","description":"Istanbul calendar date this row is for"},"lead":{"type":"integer","minimum":1,"maximum":7,"description":"valid - issued in days"},"tmax":{"$ref":"#/components/schemas/DayValue"},"tmin":{"$ref":"#/components/schemas/DayValue"},"tmean":{"$ref":"#/components/schemas/DayValue"},"raw":{"$ref":"#/components/schemas/RawFields"},"precip":{"$ref":"#/components/schemas/Precip"},"raw_hres":{"type":"object","description":"uncorrected ECMWF HRES value the model started from","properties":{"tmax":{"type":["number","null"]},"tmin":{"type":["number","null"]},"tmean":{"type":["number","null"]}}}},"required":["valid","lead","tmax","tmin","tmean"]},"Forecast":{"type":"object","properties":{"place":{"type":"string","description":"the calculator's name (ASCII for provinces)"},"display_name":{"type":"string","description":"proper Turkish spelling of place"},"province":{"type":"string"},"province_display_name":{"type":"string"},"kind":{"type":"string","enum":["place","district"],"description":"place = province"},"lat":{"type":"number"},"lon":{"type":"number"},"issued":{"type":"string","format":"date","description":"issue date, Istanbul"},"cycle":{"type":"string","description":"HRES run: 00Z or 12Z (UTC hour)"},"model_version":{"type":"string"},"produced_at":{"type":"string","format":"date-time","description":"data time, Istanbul with +03:00 offset"},"method":{"type":"string","enum":["station model","transfer","transfer+lapse"],"description":"'station model' for provinces with their own station; 'transfer' (HRES gradient from the anchor station) or 'transfer+lapse' (also an elevation correction) for districts and for provinces without a station model"},"elev_diff_m":{"type":"number","description":"district's elevation minus its anchor station's, only applied for transfer+lapse"},"verified_against":{"type":"object","properties":{"station":{"type":"string","description":"WMO station id"},"distance_km":{"type":"number"}}},"days":{"type":"array","minItems":7,"maxItems":7,"items":{"$ref":"#/components/schemas/Day"}},"precip_model_version":{"type":["string","null"],"description":"the precipitation bundle that produced days[].precip"},"products":{"type":"object","description":"what is corrected and what is raw: the notes for `raw`, `precip` and the path of the hourly twin","properties":{"raw":{"type":"string"},"precip":{"type":"string"},"hourly":{"type":["string","null"]}}},"stations":{"type":"object","description":"province responses only: WMO station id -> that station's own `days` array (no coordinates; cross-reference the id against external WMO station lists)","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Day"}}}},"required":["place","display_name","province","province_display_name","kind","issued","cycle","produced_at","method","days"]},"Alert":{"type":"object","required":["valid","type"],"properties":{"valid":{"type":"string","format":"date"},"type":{"type":"string","enum":["frost","heat","sudden_change"]},"level":{"type":"string","enum":["likely","possible"],"description":"frost: likely if tmin <= 0, possible if tmin.p05 <= 0; heat: likely if tmax >= 35, possible if tmax.p95 >= 35; absent for sudden_change"},"tmin":{"type":"number","description":"frost likely"},"tmin_p05":{"type":"number","description":"frost possible"},"tmax":{"type":"number","description":"heat likely"},"tmax_p95":{"type":"number","description":"heat possible"},"delta_tmean":{"type":"number","description":"sudden_change: day-to-day change of the daily mean, degC (|delta| >= 6)"}}},"Alerts":{"type":"object","description":"the Forecast header fields (everything but days/stations), plus the alerts list (empty when nothing is flagged)","properties":{"place":{"type":"string","description":"the calculator's name (ASCII for provinces)"},"display_name":{"type":"string","description":"proper Turkish spelling of place"},"province":{"type":"string"},"province_display_name":{"type":"string"},"kind":{"type":"string","enum":["place","district"],"description":"place = province"},"lat":{"type":"number"},"lon":{"type":"number"},"issued":{"type":"string","format":"date","description":"issue date, Istanbul"},"cycle":{"type":"string","description":"HRES run: 00Z or 12Z (UTC hour)"},"model_version":{"type":"string"},"produced_at":{"type":"string","format":"date-time","description":"data time, Istanbul with +03:00 offset"},"method":{"type":"string","enum":["station model","transfer","transfer+lapse"],"description":"'station model' for provinces with their own station; 'transfer' (HRES gradient from the anchor station) or 'transfer+lapse' (also an elevation correction) for districts and for provinces without a station model"},"elev_diff_m":{"type":"number","description":"district's elevation minus its anchor station's, only applied for transfer+lapse"},"verified_against":{"type":"object","properties":{"station":{"type":"string","description":"WMO station id"},"distance_km":{"type":"number"}}},"precip_model_version":{"type":["string","null"],"description":"the precipitation bundle that produced days[].precip"},"products":{"type":"object","description":"what is corrected and what is raw: the notes for `raw`, `precip` and the path of the hourly twin","properties":{"raw":{"type":"string"},"precip":{"type":"string"},"hourly":{"type":["string","null"]}}},"alerts":{"type":"array","items":{"$ref":"#/components/schemas/Alert"}}},"required":["place","display_name","province","province_display_name","kind","issued","cycle","produced_at","method","alerts"]},"Hourly":{"type":"object","required":["place","issued","cycle","days"],"properties":{"place":{"type":"string","description":"the calculator's name (ASCII for provinces)"},"display_name":{"type":"string","description":"proper Turkish spelling of place"},"province":{"type":"string"},"province_display_name":{"type":"string"},"kind":{"type":"string","enum":["place","district"],"description":"place = province"},"lat":{"type":"number"},"lon":{"type":"number"},"issued":{"type":"string","format":"date","description":"issue date, Istanbul"},"cycle":{"type":"string","description":"HRES run: 00Z or 12Z (UTC hour)"},"model_version":{"type":"string"},"produced_at":{"type":"string","format":"date-time","description":"data time, Istanbul with +03:00 offset"},"method":{"type":"string","enum":["station model","transfer","transfer+lapse"],"description":"'station model' for provinces with their own station; 'transfer' (HRES gradient from the anchor station) or 'transfer+lapse' (also an elevation correction) for districts and for provinces without a station model"},"note":{"type":"string"},"forecast":{"type":"string","description":"the daily file this curve belongs to"},"days":{"type":"array","minItems":1,"maxItems":7,"items":{"type":"object","required":["valid","lead","t","t_raw"],"properties":{"valid":{"type":"string","format":"date"},"lead":{"type":"integer","minimum":1,"maximum":7},"t":{"type":"array","minItems":24,"maxItems":24,"items":{"type":["number","null"]},"description":"°C at local hour 0..23 (Istanbul), the served curve"},"t_raw":{"type":"array","minItems":24,"maxItems":24,"items":{"type":["number","null"]},"description":"°C, ECMWF HRES's own curve interpolated to the hour"}}}}}},"AqDay":{"type":"object","required":["valid","lead"],"properties":{"valid":{"type":"string","format":"date"},"lead":{"type":"integer","minimum":1,"maximum":3},"pm25":{"type":["number","null"],"description":"daily mean, µg/m³"},"pm10":{"type":["number","null"],"description":"daily mean, µg/m³"},"no2":{"type":["number","null"],"description":"daily mean, µg/m³"},"o3":{"type":["number","null"],"description":"daily mean, µg/m³"},"so2":{"type":["number","null"],"description":"daily mean, µg/m³"},"co":{"type":["number","null"],"description":"daily mean, µg/m³"},"persistence":{"type":"object","description":"the D-1 observed daily mean per pollutant (the naive baseline), µg/m³","additionalProperties":{"type":["number","null"]}}}},"AqStation":{"type":"object","required":["station","name","lat","lon","days"],"properties":{"station":{"type":"string","description":"SİM/UHKİA station key"},"name":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"province":{"type":"string"},"district":{"type":["string","null"],"description":"the calculator's district the coordinates fall in"},"days":{"type":"array","items":{"$ref":"#/components/schemas/AqDay"}}}},"Aq":{"type":"object","required":["province","slug","issued","aq_model_version","units","pollutants","stations"],"properties":{"province":{"type":"string"},"display_name":{"type":"string"},"slug":{"type":"string"},"issued":{"type":"string","format":"date","description":"the 00Z issue date; observations to the end of the day before"},"aq_model_version":{"type":"string"},"units":{"type":"string","const":"µg/m³"},"pollutants":{"type":"array","items":{"type":"string"}},"leads":{"type":"array","items":{"type":"integer"}},"note":{"type":"string"},"stations":{"type":"array","items":{"$ref":"#/components/schemas/AqStation"}}}},"AqStations":{"type":"object","required":["issued","count","stations"],"properties":{"issued":{"type":"string","format":"date"},"aq_model_version":{"type":"string"},"count":{"type":"integer"},"stations":{"type":"array","items":{"type":"object","required":["station","name","lat","lon","province","path","file"],"properties":{"station":{"type":"string"},"name":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"district":{"type":["string","null"]},"province":{"type":"string"},"path":{"type":"string","description":"province slug"},"file":{"type":"string","description":"/v1/aq/{il}.json holding this station"}}}}}},"Status":{"type":"object","properties":{"time":{"type":"string","format":"date-time","description":"when the files were rendered (publisher time, +03:00); not the data time"},"model_version":{"type":["string","null"]},"latest_run":{"type":["string","null"],"description":"<issue date>T<cycle>, e.g. 2026-09-24T00"},"produced_at":{"type":["string","null"],"format":"date-time","description":"data time, Istanbul with +03:00 offset"},"provinces_served":{"type":"integer"},"provinces_with_forecast":{"type":"integer","description":"provinces with their own station model; see missing for what 404s"},"districts_total":{"type":"integer"},"districts_with_forecast":{"type":"integer","description":"forecast rows of kind district, which include provinces served by transfer"},"stations":{"type":"integer"},"hres_latest_run":{"type":"object","description":"newest ECMWF HRES input per cycle (YYYYMMDD)","additionalProperties":{"type":["string","null"]}},"synop_latest_day":{"type":["string","null"],"description":"newest observation day used for verification"},"stale":{"type":["boolean","null"],"description":"today_istanbul > issued + 1 day, at export"},"age_hours":{"type":["number","null"],"description":"hours between produced_at and the export"},"next_run_expected":{"type":["string","null"],"format":"date-time","description":"usual publish time of the next run, Istanbul (+03:00); in the past = the calculator is late"},"missing":{"type":"object","required":["provinces","districts"],"description":"slugs/paths that answer 404 in this run","properties":{"provinces":{"type":"array","items":{"type":"string"}},"districts":{"type":"array","items":{"type":"string"}}}}},"required":["time","model_version","latest_run","produced_at","provinces_served","provinces_with_forecast","districts_total","districts_with_forecast","stale","age_hours","next_run_expected","missing"]},"Place":{"type":"object","required":["name","display_name","slug","path","lat","lon"],"properties":{"name":{"type":"string","description":"the calculator's spelling (ASCII for provinces)"},"display_name":{"type":"string","description":"proper Turkish spelling, for display"},"slug":{"type":"string"},"path":{"type":"string","description":"use as /v1/forecast/{path}.json: 'mugla' for a province, 'mugla/bodrum' for a district"},"lat":{"type":"number"},"lon":{"type":"number"},"elev_m":{"type":["number","null"]}}},"Places":{"type":"object","required":["generated_at","provinces"],"properties":{"generated_at":{"type":"string","format":"date-time"},"provinces":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Place"},{"type":"object","required":["districts"],"properties":{"districts":{"type":"array","items":{"$ref":"#/components/schemas/Place"}}}}]}}}},"PlacesMin":{"type":"object","required":["columns","rows"],"properties":{"generated_at":{"type":"string","format":"date-time"},"note":{"type":"string"},"columns":{"type":"array","items":{"type":"string"},"const":["path","name","lat","lon"]},"rows":{"type":"array","items":{"type":"array","prefixItems":[{"type":"string"},{"type":"string"},{"type":"number"},{"type":"number"}],"minItems":4,"maxItems":4}}}},"Verification":{"type":"object","required":["place","window_days","issue_days","truth","by_lead"],"properties":{"place":{"type":"string"},"window_days":{"type":"integer"},"issue_days":{"type":"integer"},"truth":{"type":"string"},"by_lead":{"type":"object","description":"tmax / tmin / tmean, each keyed by lead (1..7)","additionalProperties":{"type":"object","additionalProperties":{"type":"object","required":["mae","mae_raw_hres","bias","coverage90","n"],"properties":{"mae":{"type":["number","null"],"description":"mean absolute error vs the station thermometer, C; null when n is 0"},"mae_raw_hres":{"type":["number","null"],"description":"same for raw ECMWF HRES (the baseline)"},"bias":{"type":["number","null"],"description":"mean forecast - observation, C"},"coverage90":{"type":["number","null"],"description":"share of observations inside p05..p95 (target 0.9)"},"n":{"type":"integer","description":"scored forecasts with an observation (missing observations are not counted)"}}}}}}},"Districts":{"type":"object","required":["province","districts"],"properties":{"province":{"type":"string"},"districts":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Place"},{"type":"object","required":["has_forecast"],"properties":{"has_forecast":{"type":"boolean"}}}]}}}},"SearchShard":{"type":"object","required":["prefix","entries"],"properties":{"prefix":{"type":"string"},"entries":{"type":"array","items":{"type":"object","required":["name","kind","path","slug","offset","has_forecast"],"properties":{"name":{"type":"string","description":"display spelling"},"kind":{"type":"string","enum":["province","district","settlement","neighbourhood"]},"district":{"type":["string","null"]},"province":{"type":"string"},"path":{"type":"string","description":"the district (or province) to fetch: /v1/forecast/{path}.json"},"slug":{"type":"string","description":"folded name, spaces as hyphens: compare your folded query against this"},"lat":{"type":"number"},"lon":{"type":"number"},"elev_m":{"type":["number","null"]},"elev_diff_m":{"type":"number","description":"place elevation minus district elevation, clipped to +-1500 m"},"offset":{"type":"object","required":["tmax","tmin","tmean"],"description":"°C to add to value, p05 and p95 of each day","properties":{"tmax":{"type":"number"},"tmin":{"type":"number"},"tmean":{"type":"number"}}},"has_forecast":{"type":"boolean"}}}}}}}}}