{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"Haze Monitor Public API","summary":"Read-only Southeast Asian air-quality observations, model estimates, weather and map data.","description":"The Haze Monitor API exposes public observations used by hazemonitor.com. No API key is required. Check timestamps before using readings, respect response Cache-Control headers, and use official DOE or NEA sources for public-health guidance.","version":"1.0.0","contact":{"name":"Haze Monitor","url":"https://hazemonitor.com/contact","email":"mohtashammurshid@gmail.com"}},"servers":[{"url":"https://hazemonitor.com","description":"Production, read-only public data"}],"externalDocs":{"description":"Developer guide and quickstart","url":"https://hazemonitor.com/developers"},"tags":[{"name":"Air quality","description":"Current and historical pollutant index observations."},{"name":"Context","description":"Optional place, weather and boundary context for air-quality displays."}],"security":[],"paths":{"/api/regional-air-quality":{"get":{"operationId":"getRegionalModelAirQuality","summary":"Get modelled Southeast Asia air quality","description":"CAMS via Open-Meteo estimates for selected cities in Thailand, Indonesia or Vietnam. Modelled US AQI and PM2.5 with validity times and a separate next-24-hour forecast; not station observations or official national indices.","tags":["Air quality"],"parameters":[{"name":"country","in":"query","required":true,"description":"Country whose selected city estimates to return.","schema":{"type":"string","enum":["thailand","indonesia","vietnam"]}}],"responses":{"200":{"description":"Model estimates. Inspect stale, partial and each validAt timestamp.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"country":{"type":"string","enum":["thailand","indonesia","vietnam"]},"source":{"type":"string","const":"CAMS via Open-Meteo"},"kind":{"type":"string","const":"model"},"fetchedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"stale":{"type":"boolean"},"partial":{"type":"boolean"},"cities":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"current":{"anyOf":[{"type":"object","properties":{"validAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"aqi":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"pm25":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]}},"required":["validAt","aqi","pm25"],"additionalProperties":false},{"type":"null"}]},"forecast":{"type":"array","items":{"type":"object","properties":{"validAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"aqi":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"pm25":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]}},"required":["validAt","aqi","pm25"],"additionalProperties":false}}},"required":["slug","current","forecast"],"additionalProperties":false}}},"required":["country","source","kind","fetchedAt","stale","partial","cities"],"additionalProperties":false}}}},"400":{"description":"Unknown or missing country.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"Unsupported method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"Model feed unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/singapore/estimated-history":{"get":{"operationId":"getSingaporeEstimatedPm25AqiHistory","summary":"Get PM2.5 US AQI history","description":"Converts each NEA 24-hour PM2.5 concentration before aggregation. Missing source data remains unavailable. Official PSI history is unchanged.","tags":["Air quality"],"parameters":[{"name":"station","in":"query","required":true,"description":"Singapore region: central, north, south, east, west.","schema":{"type":"string"}},{"name":"range","in":"query","required":true,"description":"Daily means for a month, or monthly means for a year.","schema":{"type":"string","enum":["month","year"]}}],"responses":{"200":{"description":"Calculated AQI means, extremes and eligible/excluded observation counts.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"metric":{"type":"string","const":"estimated-us-aqi-pm25"},"stationId":{"type":"string"},"range":{"type":"string","enum":["month","year"]},"observedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}]},"availableFrom":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}]},"points":{"type":"array","items":{"type":"object","properties":{"observedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"aqi":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"low":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"high":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"count":{"type":"integer","minimum":0,"maximum":9007199254740991},"excludedCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["observedAt","aqi","low","high","count","excludedCount"],"additionalProperties":false}}},"required":["metric","stationId","range","observedAt","availableFrom","points"],"additionalProperties":false}}}},"400":{"description":"Invalid station or range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"Unsupported method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Archive unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/air-quality/estimated-history":{"get":{"operationId":"getEstimatedPm25AqiHistory","summary":"Get PM2.5 US AQI history","description":"Converts each identified PM2.5 observation before aggregation. Unknown and other pollutants are excluded; missing buckets remain null. Original DOE API history is unchanged.","tags":["Air quality"],"parameters":[{"name":"station","in":"query","required":true,"description":"DOE station identifier.","schema":{"type":"string"}},{"name":"range","in":"query","required":true,"description":"Daily means for a month, or monthly means for a year.","schema":{"type":"string","enum":["month","year"]}}],"responses":{"200":{"description":"Calculated AQI means, extremes and eligible/excluded observation counts.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"metric":{"type":"string","const":"estimated-us-aqi-pm25"},"stationId":{"type":"string"},"range":{"type":"string","enum":["month","year"]},"observedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}]},"availableFrom":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}]},"points":{"type":"array","items":{"type":"object","properties":{"observedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"aqi":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"low":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"high":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"count":{"type":"integer","minimum":0,"maximum":9007199254740991},"excludedCount":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["observedAt","aqi","low","high","count","excludedCount"],"additionalProperties":false}}},"required":["metric","stationId","range","observedAt","availableFrom","points"],"additionalProperties":false}}}},"400":{"description":"Invalid station or range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"Unsupported method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Archive unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/air-quality":{"get":{"operationId":"getMalaysiaAirQuality","summary":"Get current Malaysia API/IPU readings","description":"Returns the latest available Department of Environment Malaysia observations for all reporting stations. Each station includes its own observation time; the response is not a forecast.","tags":["Air quality"],"responses":{"200":{"description":"Current station observations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AirQualitySnapshot"}}}},"405":{"description":"The endpoint was called with a method other than GET or HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"The current or archived DOE observations could not be loaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/air-quality/history":{"get":{"operationId":"getMalaysiaAirQualityHistory","summary":"Get Malaysia API/IPU history","description":"With no query parameters, returns recent hourly readings for all stations. With both station and range, returns a 30-day or 12-month aggregate series for one station.","tags":["Air quality"],"parameters":[{"name":"station","in":"query","required":false,"description":"DOE station identifier. Required when range is supplied.","schema":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[a-zA-Z0-9_-]+$"},"example":"CA16W"},{"name":"range","in":"query","required":false,"description":"Aggregate period. Supply station with this parameter. Omit both parameters for recent hourly history.","schema":{"type":"string","enum":["month","year"]}}],"responses":{"200":{"description":"Recent hourly history or a station aggregate series.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AirQualityHistory"},{"$ref":"#/components/schemas/ArchiveSeries"}]}}}},"400":{"description":"The station and range parameter combination is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"The endpoint was called with a method other than GET or HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"Historical observations could not be loaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/singapore":{"get":{"operationId":"getSingaporeAirQuality","summary":"Get Singapore PSI and PM2.5 readings","description":"Returns NEA observations for all five Singapore regions. Omit range for current data or set range=24h for recent observations. PSI and PM2.5 are separate measurements.","tags":["Air quality"],"parameters":[{"name":"range","in":"query","required":false,"description":"Include recent observations when set to 24h.","schema":{"type":"string","enum":["24h"]}}],"responses":{"200":{"description":"Current or recent Singapore regional observations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SingaporeSnapshot"}}}},"400":{"description":"The range parameter is unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"The endpoint was called with a method other than GET or HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"Singapore observations could not be loaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/geocode":{"get":{"operationId":"searchLocations","summary":"Search for a place","description":"Searches public geocoding providers and returns up to 14 merged place results. Use the coordinates with the weather endpoint or to compare a place with monitoring stations.","tags":["Context"],"parameters":[{"name":"query","in":"query","required":true,"description":"Place name to search for.","schema":{"type":"string","minLength":2,"maxLength":100},"example":"Kuala Lumpur"}],"responses":{"200":{"description":"Matching places, possibly an empty list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationSearchResponse"}}}},"400":{"description":"The query is missing or outside the accepted length.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"The endpoint was called with a method other than GET or HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"All configured geocoding providers failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/weather":{"get":{"operationId":"getWeatherContext","summary":"Get weather context for coordinates","description":"Returns current Open-Meteo weather context for one coordinate pair. This data can help explain local conditions but does not change the reported air-quality index.","tags":["Context"],"parameters":[{"name":"latitude","in":"query","required":true,"description":"Latitude in decimal degrees.","schema":{"type":"number","minimum":-90,"maximum":90},"example":3.139},{"name":"longitude","in":"query","required":true,"description":"Longitude in decimal degrees.","schema":{"type":"number","minimum":-180,"maximum":180},"example":101.687}],"responses":{"200":{"description":"Current weather context for the coordinates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Weather"}}}},"400":{"description":"One or both coordinates are missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"405":{"description":"The endpoint was called with a method other than GET or HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"Weather context could not be loaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/state-boundaries":{"get":{"operationId":"getMalaysiaStateBoundaries","summary":"Get Malaysia state boundaries","description":"Returns simplified GeoJSON Polygon and MultiPolygon features for Malaysian administrative level 1 boundaries. This endpoint contains map geometry, not air-quality readings.","tags":["Context"],"responses":{"200":{"description":"A GeoJSON FeatureCollection of state boundaries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateBoundaryCollection"}}}},"405":{"description":"The endpoint was called with a method other than GET or HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"502":{"description":"State boundary geometry could not be loaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"components":{"schemas":{"ApiError":{"type":"object","additionalProperties":false,"required":["error","code","message","resolution","requestId"],"properties":{"error":{"type":"string","description":"Backward-compatible copy of message."},"code":{"type":"string","description":"Stable machine-readable error code.","enum":["AIR_QUALITY_UNAVAILABLE","GEOCODING_UNAVAILABLE","HISTORY_UNAVAILABLE","INVALID_COORDINATES","INVALID_HISTORY_QUERY","INVALID_QUERY","INVALID_RANGE","METHOD_NOT_ALLOWED","NOT_FOUND","SINGAPORE_DATA_UNAVAILABLE","STATE_BOUNDARIES_UNAVAILABLE","WEATHER_UNAVAILABLE"]},"message":{"type":"string","description":"Short explanation of the failure."},"resolution":{"type":"string","description":"Specific next action the caller can take."},"requestId":{"type":"string","format":"uuid","description":"Request identifier for support and log correlation."},"fetchedAt":{"type":"string","format":"date-time","description":"When the failed data fetch was attempted, when applicable."}}},"AirQualityCategory":{"type":"string","enum":["Good","Moderate","Unhealthy","Very Unhealthy","Hazardous","Unavailable"]},"AirQualityStation":{"type":"object","additionalProperties":false,"required":["id","name","fullName","state","region","latitude","longitude","api","pm10Api","category","pollutant","observedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"fullName":{"type":"string"},"state":{"type":"string"},"region":{"type":"string"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"api":{"type":["number","null"],"minimum":0},"pm10Api":{"type":["number","null"],"minimum":0},"category":{"$ref":"#/components/schemas/AirQualityCategory"},"pollutant":{"type":["string","null"]},"observedAt":{"type":["string","null"],"format":"date-time"},"isFallback":{"type":"boolean"}}},"AirQualitySnapshot":{"type":"object","additionalProperties":false,"required":["source","sourceUrl","fetchedAt","observedAt","stationCount","reportingCount","stations"],"properties":{"source":{"type":"string","const":"Department of Environment Malaysia"},"sourceUrl":{"type":"string","format":"uri"},"fetchedAt":{"type":"string","format":"date-time"},"observedAt":{"type":["string","null"],"format":"date-time"},"stationCount":{"type":"integer","minimum":0},"reportingCount":{"type":"integer","minimum":0},"stations":{"type":"array","items":{"$ref":"#/components/schemas/AirQualityStation"}}}},"HistoryReading":{"type":"object","additionalProperties":false,"required":["observedAt","api"],"properties":{"observedAt":{"type":"string","format":"date-time"},"api":{"type":["number","null"],"minimum":0},"pollutant":{"type":["string","null"]}}},"AirQualityHistory":{"type":"object","additionalProperties":false,"required":["source","fetchedAt","observedAt","stations"],"properties":{"source":{"type":"string","const":"Department of Environment Malaysia"},"fetchedAt":{"type":"string","format":"date-time"},"observedAt":{"type":["string","null"],"format":"date-time"},"stations":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","readings"],"properties":{"id":{"type":"string"},"readings":{"type":"array","items":{"$ref":"#/components/schemas/HistoryReading"}}}}}}},"ArchivePoint":{"type":"object","additionalProperties":false,"required":["observedAt","api","low","high","count"],"properties":{"observedAt":{"type":"string","format":"date-time"},"api":{"type":["number","null"],"minimum":0},"low":{"type":["number","null"],"minimum":0},"high":{"type":["number","null"],"minimum":0},"count":{"type":"integer","minimum":0}}},"ArchiveSeries":{"type":"object","additionalProperties":false,"required":["source","stationId","range","fetchedAt","observedAt","availableFrom","points"],"properties":{"source":{"type":"string","const":"Department of Environment Malaysia"},"stationId":{"type":"string"},"range":{"type":"string","enum":["month","year"]},"fetchedAt":{"type":"string","format":"date-time"},"observedAt":{"type":["string","null"],"format":"date-time"},"availableFrom":{"type":["string","null"],"format":"date-time"},"points":{"type":"array","items":{"$ref":"#/components/schemas/ArchivePoint"}}}},"RegionalValues":{"type":"object","additionalProperties":false,"required":["central","north","south","east","west"],"properties":{"central":{"type":["number","null"],"minimum":0},"north":{"type":["number","null"],"minimum":0},"south":{"type":["number","null"],"minimum":0},"east":{"type":["number","null"],"minimum":0},"west":{"type":["number","null"],"minimum":0}}},"SingaporeObservation":{"type":"object","additionalProperties":false,"required":["observedAt","values"],"properties":{"observedAt":{"type":"string","format":"date-time"},"values":{"$ref":"#/components/schemas/RegionalValues"},"archivedRegions":{"type":"array","items":{"type":"string","enum":["central","north","south","east","west"]}}}},"SingaporeSnapshot":{"type":"object","additionalProperties":false,"required":["source","fetchedAt","psi","pm25","partial"],"properties":{"source":{"type":"string","const":"National Environment Agency Singapore"},"fetchedAt":{"type":"string","format":"date-time"},"psi":{"type":"array","items":{"$ref":"#/components/schemas/SingaporeObservation"}},"pm25":{"type":"array","description":"1-hour PM2.5 concentrations in µg/m³.","items":{"$ref":"#/components/schemas/SingaporeObservation"}},"pm25_24h":{"type":"array","description":"24-hour PM2.5 concentrations in µg/m³, used for US AQI calculation.","items":{"$ref":"#/components/schemas/SingaporeObservation"}},"partial":{"type":"boolean"}}},"LocationSearchResponse":{"type":"object","additionalProperties":false,"required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/Location"},"maxItems":14}}},"Location":{"type":"object","additionalProperties":false,"required":["id","name","latitude","longitude","countryCode","country","admin1","admin2"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"countryCode":{"type":["string","null"]},"country":{"type":["string","null"]},"admin1":{"type":["string","null"]},"admin2":{"type":["string","null"]}}},"Weather":{"type":"object","additionalProperties":false,"required":["source","latitude","longitude","observedAt","temperature","humidity","windSpeed","windDirection","visibilityKm","weatherCode"],"properties":{"source":{"type":"string","const":"Open-Meteo"},"latitude":{"type":"number"},"longitude":{"type":"number"},"observedAt":{"type":"string"},"temperature":{"type":"number"},"humidity":{"type":"number"},"windSpeed":{"type":"number"},"windDirection":{"type":"number"},"visibilityKm":{"type":"number"},"weatherCode":{"type":"number"}}},"StateBoundaryCollection":{"type":"object","additionalProperties":false,"required":["type","features"],"properties":{"type":{"type":"string","const":"FeatureCollection"},"features":{"type":"array","items":{"type":"object","required":["type","geometry","properties"],"properties":{"type":{"type":"string","const":"Feature"},"geometry":{"oneOf":[{"type":"object","required":["type","coordinates"],"properties":{"type":{"type":"string","const":"Polygon"},"coordinates":{"type":"array","items":{"type":"array","items":{"$ref":"#/components/schemas/Position"}}}}},{"type":"object","required":["type","coordinates"],"properties":{"type":{"type":"string","const":"MultiPolygon"},"coordinates":{"type":"array","items":{"type":"array","items":{"type":"array","items":{"$ref":"#/components/schemas/Position"}}}}}}]},"properties":{"type":"object","required":["shapeName","shapeISO","shapeID","shapeGroup","shapeType"],"properties":{"shapeName":{"type":"string"},"shapeISO":{"type":"string"},"shapeID":{"type":"string"},"shapeGroup":{"type":"string"},"shapeType":{"type":"string"}},"additionalProperties":true}}}}}},"Position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"}],"minItems":2}}}}