Disaster events API
The DPIP disaster-events API gathers disaster information issued by the Central Weather Administration (CWA), the National Science and Technology Center for Disaster Reduction (NCDR), the Water Resources Agency, the Directorate-General of Personnel Administration (DGPA), and other agencies, and stores it in one event format. ExpTech only relays this information and does not issue these alerts itself. You can query events that are active now, nationwide or for one township, events from the last 3 days, and the affected area of one event (GeoJSON). Titles and body text can be requested in Simplified Chinese, English, Japanese, and other languages with the lang parameter.
Data license
Section titled “Data license”AttributionData: CWA and other issuing agencies, ExpTech Studio (exptech.dev)
- CWA, NCDR, Water Resources Agency, DGPA and other issuing agencies: Each issuing agency's terms also apply. The issuer of each event is in its
authorfield; credit it when you show a single event.
Where to show it, examples and commercial-use requests: Data licensing and attribution.
Authentication
Section titled “Authentication”No API Token is required.
Region codes
Section titled “Region codes”The region path parameter and the event area field both use the 3-digit postal code of a township, town, or district. For example, 105 is Songshan District, Taipei City, and 970 is Hualien City, Hualien County. These are the same township codes as the township hourly forecast.
- A township endpoint returns only events whose
areacontains that code. You do not filter them yourself. - An event with
areaof[](for example a thunderstorm or a road closure whose area is a polygon) appears only on the nationwide endpoints. For those, usehasPolygonand/event/{id}to get the area and test it yourself.
Language
Section titled “Language”All five endpoints accept a lang query parameter, one language at a time. Omitting it, a blank value, or a value that cannot be recognized is treated as zh. That does not return 400.
lang |
Language | How it is produced |
|---|---|---|
zh |
Traditional Chinese (Taiwan) | Original text |
zh_Hant_HK |
Traditional Chinese (Hong Kong) | Converted on request |
zh_Hans |
Simplified Chinese | Converted on request |
en |
English | Translated in the background |
ja |
Japanese | Translated in the background |
ko |
Korean | Translated in the background |
vi |
Vietnamese | Translated in the background |
th |
Thai | Translated in the background |
id |
Indonesian | Translated in the background |
fil |
Filipino | Translated in the background |
Parsing rules:
- When there are several values, only the first is used. When there is a comma, only the first segment is used (
en,jais treated asen). - Surrounding whitespace is removed, and
-is replaced with_(zh-TWequalszh_TW). - An exact match with the table is used.
- Aliases, case-insensitive:
zh_TW,zh_Hant, andzh_Hant_TWmap tozh;yue,zh_HK,yue_Hant, andzh_Hant_MOmap tozh_Hant_HK;zh_CN,zh_SG, andzh_Hans_CNmap tozh_Hans. - Otherwise the primary language before the first
_is used when it is in the table (en_USbecomesen,ja_JPbecomesja). - Everything else is
zh.
Only title, subtitle, and description are converted or translated. raw is always the original Traditional Chinese from Taiwan. For a language that is translated in the background, if any of the three fields has no translation, the whole entry falls back to zh (the lang field is zh). It does not mix languages. A later request to the same URL returns the translation, and the ETag changes. To see whether a translation is ready, compare each entry’s lang with the language you requested.
Active events nationwide
Section titled “Active events nationwide”Events nationwide that have not expired yet (expires is later than now). Polygon areas are not included.
langQuery parameter. Language. See the Language section
curl "https://api.core-tnn1.exptech.dev/api/v2/dpip/realtime/list"const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/dpip/realtime/list");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);import requests
res = requests.get( "https://api.core-tnn1.exptech.dev/api/v2/dpip/realtime/list", timeout=10,)res.raise_for_status()print(res.json())Success. [] when there are no events
[ { "id": "1794632460", "status": 1, "type": "thunderstorm", "author": "cwa", "send": 1794632400000, "expires": 1794636000000, "title": "大雷雨即時訊息", "subtitle": "雷雨即時訊息", "description": "氣象署發布大雷雨即時訊息,持續時間至 14 時。", "lang": "zh", "area": [], "hasPolygon": true }]Not modified (If-None-Match matched). No bodyNo response body
Try it
Response fields
Section titled “Response fields”The response is an array of events. Every entry from the four list endpoints has this shape.
| Field | Type | Description |
|---|---|---|
[].id | string | Event id. A string of digits (the Unix seconds at the moment it was written), unique across all events. The unit differs from send. Do not use it as a time |
[].status | number | 1: the source marks it as an official issue. 0: anything else (for example an exercise or a test) |
[].type | string | Event type. See Event types |
[].author | string | Issuing-source id, for example cwa, ncdr, wra, dgpa. Some types take it straight from the source data, and the format is not fixed |
[].send | number | Issue time, Unix milliseconds |
[].expires | number | Expiry time, Unix milliseconds |
[].title | string | Title |
[].subtitle | string | Subtitle |
[].description | string | Body. A township endpoint may use that township's summary. See description and raw |
[].raw | string | Optional. The nationwide original text. Present only on a township endpoint when description uses that township's summary. Not translated |
[].lang | string | The language this entry actually uses. zh when the translation is incomplete |
[].area | number[] | Region codes of affected townships (3-digit postal codes). May be [] |
[].hasPolygon | boolean | true means /event/{id} can return a polygon area |
[].addition | object | Optional. Extra data that depends on the type. See Extra data (addition) |
Active events for a township
Section titled “Active events for a township”Events whose area contains the township and that have not expired for that township.
regionPath parameter. 3-digit postal code, for example 105
langQuery parameter. Language
curl "https://api.core-tnn1.exptech.dev/api/v2/dpip/realtime/<region>"const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/dpip/realtime/<region>");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);import requests
res = requests.get( "https://api.core-tnn1.exptech.dev/api/v2/dpip/realtime/<region>", timeout=10,)res.raise_for_status()print(res.json())Success. [] when there are no events
[ { "id": "1794626412", "status": 1, "type": "heavy-rain", "author": "cwa", "send": 1794626400000, "expires": 1794662400000, "title": "大雨特報", "subtitle": "大雨特報", "description": "臺北市松山區今晚有局部大雨,請注意。", "raw": "東北風影響,今(14)日基隆北海岸、臺北市山區及新北市山區有局部大雨發生的機率。", "lang": "zh", "area": [ 105, 106, 110 ], "hasPolygon": false }]Not modified (If-None-Match matched). No bodyNo response body
region is not a number
{ "error": "Invalid region"}Try it
Response fields
Section titled “Response fields”Same as Active events nationwide. description and raw differ. See description and raw.
Events from the last 3 days, nationwide
Section titled “Events from the last 3 days, nationwide”Events nationwide whose send is within the last 3 days, including ones that have expired.
langQuery parameter. Language
curl "https://api.core-tnn1.exptech.dev/api/v2/dpip/history/list"const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/dpip/history/list");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);import requests
res = requests.get( "https://api.core-tnn1.exptech.dev/api/v2/dpip/history/list", timeout=10,)res.raise_for_status()print(res.json())Success. [] when there are no events
[ { "id": "1794630005", "status": 1, "type": "earthquake", "author": "cwa", "send": 1794630005000, "expires": 1794716405000, "title": "地震報告", "subtitle": "地震報告 [115071]", "description": "11/14 12:16左右,花蓮縣近海發生地震。震源深度15公里,地震規模M5.1,花蓮縣觀測到最大震度4級。", "lang": "zh", "area": [ 970, 971, 972 ], "hasPolygon": false, "addition": { "id": "115071-2026-1114-121630" } }]Not modified (If-None-Match matched). No bodyNo response body
Try it
Response fields
Section titled “Response fields”Same as Active events nationwide.
Events from the last 3 days for a township
Section titled “Events from the last 3 days for a township”Events whose area contains the township and whose send is within the last 3 days, including ones that have expired.
regionPath parameter. 3-digit postal code, for example 105
langQuery parameter. Language
curl "https://api.core-tnn1.exptech.dev/api/v2/dpip/history/<region>"const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/dpip/history/<region>");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);import requests
res = requests.get( "https://api.core-tnn1.exptech.dev/api/v2/dpip/history/<region>", timeout=10,)res.raise_for_status()print(res.json())Success. [] when there are no events
[ { "id": "1794626412", "status": 1, "type": "heavy-rain", "author": "cwa", "send": 1794626400000, "expires": 1794662400000, "title": "Heavy Rain Advisory", "subtitle": "Heavy Rain Advisory", "description": "Localized heavy rain is expected in Songshan District, Taipei tonight.", "raw": "東北風影響,今(14)日基隆北海岸、臺北市山區及新北市山區有局部大雨發生的機率。", "lang": "en", "area": [ 105, 106, 110 ], "hasPolygon": false }]Not modified (If-None-Match matched). No bodyNo response body
region is not a number
{ "error": "Invalid region"}Try it
Response fields
Section titled “Response fields”Same as Active events nationwide. The example above is ?lang=en: raw is still the original Chinese text.
A single event
Section titled “A single event”Fetch one event by id. When it has an area, the response adds polygon (GeoJSON). Lists do not include polygon. When hasPolygon is true, call this endpoint to get it.
idPath parameter. The event id
langQuery parameter. Language
curl "https://api.core-tnn1.exptech.dev/api/v2/dpip/event/<id>"const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/dpip/event/<id>");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);import requests
res = requests.get( "https://api.core-tnn1.exptech.dev/api/v2/dpip/event/<id>", timeout=10,)res.raise_for_status()print(res.json())Success. [] when this id does not exist
[ { "id": "1794632460", "status": 1, "type": "thunderstorm", "author": "cwa", "send": 1794632400000, "expires": 1794636000000, "title": "大雷雨即時訊息", "subtitle": "雷雨即時訊息", "description": "氣象署發布大雷雨即時訊息,持續時間至 14 時。", "lang": "zh", "area": [], "hasPolygon": true, "polygon": { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 121.56, 25.03 ], [ 121.57, 25.04 ], [ 121.58, 25.02 ], [ 121.56, 25.03 ] ] ] } } ] } }]Not modified (If-None-Match matched). No bodyNo response body
Try it
Response fields
Section titled “Response fields”The response is an array. Normally it has one entry. When the id does not exist it is [] (200). Fields match Active events nationwide, plus:
| Field | Type | Description |
|---|---|---|
[].polygon | object | Optional. A GeoJSON FeatureCollection. geometry is a Polygon, coordinates are [longitude, latitude]. Present only when hasPolygon is true. The geometry is simplified (error of about 22 m) |
description follows the same rule as the nationwide endpoints (the nationwide original text, with no raw).
Event types
Section titled “Event types”These are the types currently written as events. Display a type that is not listed (use a generic icon). Do not drop the entry.
type |
Name | author |
area |
Area polygon |
addition |
Notes |
|---|---|---|---|---|---|---|
heavy-rain |
Heavy rain advisory | cwa |
Township code | No | None | Has a per-area summary |
extremely-heavy-rain |
Extremely heavy rain advisory | cwa |
Township code | No | None | Has a per-area summary |
torrential-rain |
Torrential rain advisory | cwa |
Township code | No | None | Has a per-area summary |
extremely-torrential-rain |
Extremely torrential rain advisory | cwa |
Township code | No | None | Has a per-area summary |
thunderstorm |
Significant thunderstorm advisory, tornado watch | cwa |
[] |
Yes | None | The title is a significant thunderstorm advisory or a tornado watch |
earthquake |
Earthquake report | cwa |
Every township in counties or cities where intensity was observed | No | Earthquake report id | Expires 24 hours after it is issued |
tsunami_note |
Slight sea-level change | cwa |
Coastal townships | No | Earthquake report id | Issued when magnitude is 6 or greater, depth is within 30 km, and the epicenter is at sea. Expires 24 hours after it is issued |
debrisFlowLandSlide |
Debris-flow and large-scale landslide alert | Issuing agency from the source | [] |
Yes | None | |
barrierLake |
Barrier-lake alert | Issuing agency from the source | [] |
Yes | None | |
roadClose |
Road closure | Issuing agency from the source | [] |
Yes | Closure location | |
floodSensor |
Flood sensing | wra |
[] |
Yes | Sensor station | |
seawave |
Wave observation (high waves) | ncdr |
[] |
Yes | None | Issued when a coastal station reports a wave height of 6 m or more. Expires 3 hours after the observation |
workSchlClos |
Work and school suspension | dgpa |
Township code | No | None | |
reservoirDischarge |
Reservoir discharge | wra |
Township code | No | None | Not enabled. It does not appear |
Rain advisories from lightest to heaviest: heavy-rain, extremely-heavy-rain, torrential-rain, extremely-torrential-rain.
Extra data (addition)
Section titled “Extra data (addition)”Only some types include addition. Any of these fields may be omitted:
| Type | Shape |
|---|---|
earthquake, tsunami_note |
{ "id": "earthquake report id" }, which you can use with earthquake reports |
roadClose |
areaDesc (area description), county, town, roadName, location, geocode, plus the source’s original polygon and circle strings |
floodSensor |
areaDesc, county, town, waterLevelStation (water-level station), waterLevel (water level), geocode, plus the source’s original polygon and circle strings |
polygon and circle inside addition are the source’s original strings. To draw a map, use the GeoJSON polygon from /event/{id}.
description and raw
Section titled “description and raw”The four rain advisories (heavy-rain, extremely-heavy-rain, torrential-rain, extremely-torrential-rain) have the nationwide original text and an automatically generated per-area summary.
| Endpoint | Other events | Rain advisories |
|---|---|---|
Nationwide lists, /event/{id} |
description is the original text. There is no raw |
description is the nationwide original text. There is no raw |
| Township list, and that township has a per-area summary | Does not happen | description is that township’s summary. raw is the nationwide original text |
| Township list, but that township has no per-area summary | description is the original text. There is no raw |
description is the nationwide original text. There is no raw |
A rain advisory appears first as the original text. The per-area summary is filled in later (usually within a few minutes), so description for the same id can change. Use the latest response. Do not cache the body by id. On a request for another language, if that township’s summary has no translation yet, description uses the translation of the nationwide original text first.
Advanced examples
Section titled “Advanced examples”Draw the areas of active nationwide events in MapLibre GL JS. The list has no polygon. For an event with hasPolygon set to true, request A single event to get the GeoJSON.
const API = "https://api.core-tnn1.exptech.dev";
// 1. Active events nationwide, sorted by issue time, newest first (response order is not guaranteed)const events = await fetch(`${API}/api/v2/dpip/realtime/list`).then((r) => r.json());events.sort((a, b) => b.send - a.send);
// 2. For events that have an area, fetch the single event and add polygon as a GeoJSON sourcefor (const e of events.filter((e) => e.hasPolygon)) { const [event] = await fetch(`${API}/api/v2/dpip/event/${e.id}`).then((r) => r.json()); if (!event?.polygon) continue; // [] when the event does not exist map.addSource(`dpip-${event.id}`, { type: "geojson", data: event.polygon }); map.addLayer({ id: `dpip-${event.id}`, type: "fill", source: `dpip-${event.id}`, paint: { "fill-color": "#ef4444", "fill-opacity": 0.25 }, });}- Time unit:
sendandexpiresare Unix milliseconds.idis also a time number, but it is Unix seconds, and it is only an id. - Response order is not guaranteed. Sort by
sendyourself, newest first. - A query with no data returns
[](200), which is a different status from 404. The only 400 is whenregionis not a number. - Active and last-3-days use different conditions. An event that has expired but was issued within 3 days is only in history. An event that has not expired but was issued more than 3 days ago is only in realtime.
- Events are kept for at most 7 days. After that,
/event/{id}cannot find them either. - The response has an
ETag(an MD5 without quotes).If-None-Matchmay include quotes or not. On a match the response is 304 with no body. TheETagcovers the whole response, including the language and the translation at that moment, so include the full URL (includinglang) in the cache key. The server does not sendCache-Control. - Responses support gzip (add
--compressedto curl) and allow cross-origin calls. - Sources: public disaster information from CWA, NCDR, the Water Resources Agency, DGPA, and other agencies.
