地震報告
地震報告資料來自中央氣象署(CWA)發布的地震報告,包含震央位置、規模、深度,以及各縣市、各測站的觀測震度。伺服器每隔幾秒向氣象署檢查一次新報告。適合用來做地震列表、歷史查詢與震度分布圖。
- 要即時收到新報告,請改用 SSE 串流
eq.report.v1。 - 列表(
/api/v2/eq/report)不含各地震度;需要震度分布時,用列表拿到id後再查單筆報告。
建議標示資料來源:中央氣象署、ExpTech Studio(exptech.dev)
- 中央氣象署:另須遵守中央氣象署的資料使用規範(例如政府資料開放授權條款);氣象與地震資訊以中央氣象署發布的內容為準。
標示位置、範例與商業使用申請見資料授權與來源標示。
目前不需要 API Token。
查詢地震報告列表
Section titled “查詢地震報告列表”依條件查詢地震報告,回傳陣列。預設依發震時間由新到舊、每頁 1 筆,而且只包含全臺最大震度 1 級以上的報告(見注意事項)。
limit每頁筆數,1–150。超出範圍會套用最接近的上下限。
page頁碼,1–10000。
sort排序欄位:time(發震時間)、intensity(全臺最大震度)、magnitude(規模)、depth(深度)。值相同時依報告編號由新到舊。
order排序方向:asc 或 desc。
minIntensity全臺最大震度下限,0–9(對照見「震度表示法」)。要包含震度 0 的報告請帶 minIntensity=0。
maxIntensity全臺最大震度上限,0–9。
minMagnitude規模下限,0–10。
maxMagnitude規模上限,0–10。
minDepth深度下限(公里),0–700。
maxDepth深度上限(公里),0–700。
startTime起始日期 YYYY-MM-DD(臺灣時間),包含當日 00:00:00。格式錯誤時忽略。
endTime結束日期 YYYY-MM-DD(臺灣時間),包含當日 23:59:59。格式錯誤時忽略。
city縣市名稱,完全比對,例如 花蓮縣、臺北市(用「臺」不是「台」)。只回傳該縣市有觀測震度的報告。
cityMinInt縣市震度下限。與 city 一起用時套用在該縣市;單獨使用時,任一縣市符合即列入。
cityMaxInt縣市震度上限,規則同 cityMinInt。
curl -L "https://api.core.exptech.dev/api/v2/eq/report"curl -L "https://api.core-tnn1.exptech.dev/api/v2/eq/report"curl -L "https://api.core-tyo1.exptech.dev/api/v2/eq/report"const res = await fetch("https://api.core.exptech.dev/api/v2/eq/report");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/eq/report");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);const res = await fetch("https://api.core-tyo1.exptech.dev/api/v2/eq/report");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.exptech.dev/api/v2/eq/report", timeout=10)res.raise_for_status()print(res.json())import requests
res = requests.get("https://api.core-tnn1.exptech.dev/api/v2/eq/report", timeout=10)res.raise_for_status()print(res.json())import requests
res = requests.get("https://api.core-tyo1.exptech.dev/api/v2/eq/report", timeout=10)res.raise_for_status()print(res.json())成功(沒有符合的報告時為空陣列 [])
[ { "id": "115079-2026-1109-122157", "lat": 23.62, "lon": 120.66, "depth": 10.5, "loc": "雲林縣政府東南東方 23.2 公里 (位於雲林縣古坑鄉)", "mag": 4.2, "time": 1794198117000, "int": 3, "trem": 0, "md5": "3F2A9C1E7B5D4A608E1F2C3D4B5A6978" }]參數不是正規形式,導向正規網址
HTTP/1.1 302 FoundLocation: /api/v2/eq/report?limit=20&minIntensity=4If-None-Match 與 ETag 相同,沒有內容沒有回應本文
伺服器錯誤
{ "error": "<錯誤訊息>"}試試看
回應是陣列,每個元素是一筆報告:
| 欄位 | 類型 | 說明 |
|---|---|---|
[].id | string | 報告 ID,格式 XXXXXX-YYYY-MMDD-HHMMSS。前 3 碼是民國年、接著 3 碼是氣象署報告編號(沒有編號的小區域地震為 000),後面是發震日期與時間(臺灣時間)。例:115079-2026-1109-122157。 |
[].lat | number | 震央緯度(度)。 |
[].lon | number | 震央經度(度)。 |
[].depth | number | 震源深度(公里)。 |
[].loc | string | 震央位置描述,沿用氣象署原文(可能含連續空白)。 |
[].mag | number | 芮氏規模。 |
[].time | int | 發震時間,Unix 毫秒。 |
[].int | int | 全臺最大震度,0–9(對照見「震度表示法」)。 |
[].trem | int | 保留欄位,目前固定為 0。 |
[].md5 | string | 報告內容(含各地震度)的雜湊值,32 碼大寫十六進位。內容有更新時會改變,可用來判斷是否需要重新取得單筆報告。 |
取得單筆地震報告
Section titled “取得單筆地震報告”依報告 ID 取得一筆報告,包含各縣市與各測站的震度。
id報告 ID(路徑參數),格式 XXXXXX-YYYY-MMDD-HHMMSS,例如 114000-2025-0829-100546。query 參數會被忽略。
curl "https://api.core.exptech.dev/api/v2/eq/report/<id>"curl "https://api.core-tnn1.exptech.dev/api/v2/eq/report/<id>"curl "https://api.core-tyo1.exptech.dev/api/v2/eq/report/<id>"const res = await fetch("https://api.core.exptech.dev/api/v2/eq/report/<id>");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);const res = await fetch("https://api.core-tnn1.exptech.dev/api/v2/eq/report/<id>");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);const res = await fetch("https://api.core-tyo1.exptech.dev/api/v2/eq/report/<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.exptech.dev/api/v2/eq/report/<id>", timeout=10)res.raise_for_status()print(res.json())import requests
res = requests.get( "https://api.core-tnn1.exptech.dev/api/v2/eq/report/<id>", timeout=10,)res.raise_for_status()print(res.json())import requests
res = requests.get( "https://api.core-tyo1.exptech.dev/api/v2/eq/report/<id>", timeout=10,)res.raise_for_status()print(res.json())成功
{ "id": "114000-2025-0829-100546", "lat": 22.86, "lon": 121.28, "depth": 16.9, "loc": "臺東縣政府東北方 17.5 公里 (位於臺東縣近海)", "mag": 4, "time": 1756433146000, "list": { "臺東縣": { "int": 2, "town": { "東河": { "lat": 22.97, "lon": 121.3, "int": 2 }, "鹿野": { "lat": 22.91, "lon": 121.13, "int": 2 }, "成功": { "lat": 23.1, "lon": 121.37, "int": 1 } } }, "花蓮縣": { "int": 1, "town": { "富里": { "lat": 23.2, "lon": 121.29, "int": 1 } } } }, "trem": 0}If-None-Match 與 ETag 相同,沒有內容沒有回應本文
ID 格式錯誤或查無此報告(沒有回應本文)沒有回應本文
試試看
| 欄位 | 類型 | 說明 |
|---|---|---|
id | string | 報告 ID,格式同列表。 |
lat | number | 震央緯度(度)。 |
lon | number | 震央經度(度)。 |
depth | number | 震源深度(公里)。 |
loc | string | 震央位置描述。 |
mag | number | 芮氏規模。 |
time | int | 發震時間,Unix 毫秒。 |
list | object | 各縣市震度。key 是縣市名稱(例如 臺東縣)。沒有觀測資料時為空物件 {}。 |
<縣市>.int | int | 該縣市的最大震度,0–9。 |
<縣市>.town | object | 該縣市各測站的震度,key 是測站名稱。 |
<測站>.lat | number | 測站緯度(度)。 |
<測站>.lon | number | 測站經度(度)。 |
<測站>.int | int | 測站震度,0–9。 |
trem | int | 保留欄位,目前固定為 0。 |
單筆回應沒有 int(全臺最大震度)與 md5。需要全臺最大震度時,取 list 裡各縣市 int 的最大值。
int、minIntensity、cityMinInt 等震度欄位都用 0–9 的整數表示中央氣象署震度分級:
| 數值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| 震度 | 0 級 | 1 級 | 2 級 | 3 級 | 4 級 | 5 弱 | 5 強 | 6 弱 | 6 強 | 7 級 |
依條件查列表,再用列表的 id 逐筆取各地震度(列表不含各地震度)。query 依正規形式組成(參數依字母序、不帶預設值)就不會多一次 302:
# 最近 20 筆最大震度 4 級以上的報告curl -L "https://api.core.exptech.dev/api/v2/eq/report?limit=20&minIntensity=4"
# 2024-04-03 當天(臺灣時間)所有報告,包含震度 0curl -L "https://api.core.exptech.dev/api/v2/eq/report?endTime=2024-04-03&limit=150&minIntensity=0&startTime=2024-04-03"const BASE = "https://api.core.exptech.dev";
// 1. 列表:最近 20 筆最大震度 4 級以上的報告const params = new URLSearchParams({ limit: "20", minIntensity: "4" });const listRes = await fetch(`${BASE}/api/v2/eq/report?${params}`);if (!listRes.ok) throw new Error(`HTTP ${listRes.status}`);const reports = await listRes.json();
// 2. 單筆:逐筆取各縣市與測站震度for (const r of reports) { console.log(r.id, new Date(r.time).toISOString(), `M${r.mag}`, `最大震度 ${r.int}`);
const res = await fetch(`${BASE}/api/v2/eq/report/${r.id}`); if (res.status === 404) continue; // 查無此報告 if (!res.ok) throw new Error(`HTTP ${res.status}`); const report = await res.json();
for (const [city, area] of Object.entries(report.list)) { for (const [station, s] of Object.entries(area.town)) { console.log(" ", city, area.int, station, s.int); } }}-
預設會濾掉震度 0 的報告。 列表的
minIntensity預設是1,沒帶這個參數時,全臺最大震度 0 級的報告不會出現。要列出全部報告請帶minIntensity=0。 -
參數不是正規形式時會先回 302。 列表(v2 與 v1)會把 query 正規化,跟正規形式不同就回
302導向正規網址,之後才回資料。正規形式的規則:- 參數依名稱字母序排列;
- 拿掉等於預設值的參數(例如
page=1、sort=time、limit=1); - 拿掉不認得的參數;
- 數值套用上下限並去掉多餘的零(例如
limit=500變成limit=150、minMagnitude=4.50變成minMagnitude=4.5),格式錯誤的日期會被拿掉。
瀏覽器的
fetch會自動跟隨 302;curl要加-L。依上面規則組網址可以省掉一次往返。單筆報告(/api/v2/eq/report/{id})不做正規化、不會 302。 -
參數值錯誤不會回 400。 無法解析的整數或小數會當作
0再套用上下限(例如minIntensity=abc等同minIntensity=0);sort、order不認得的值退回預設值。 -
快取與 ETag。 回應帶
ETag,請求帶相同的If-None-Match會得到304(沒有本文)。伺服器端快取 1 秒。也支援HEAD。 -
錯誤回應。 伺服器錯誤時回
500,本文是{"error": "..."},訊息只供除錯參考,請不要依內容判斷。單筆報告查不到或 ID 格式錯誤時回404,沒有回應本文。 -
時間與座標。
time是 Unix 毫秒;日期參數startTime、endTime以臺灣時間(UTC+8)解讀。震央座標四捨五入到小數 2 位。 -
列表與單筆欄位不同。 列表有
int、md5,沒有list;單筆有list,沒有int、md5。
回傳最新的 N 筆報告(依發震時間由新到舊),每筆都包含各縣市與測站震度。沒有震度、規模等篩選,也不會濾掉震度 0 的報告。
limit回傳筆數,1–50。無效值當作 1,超過 50 當作 50。
curl -L "https://api.core.exptech.dev/api/v1/eq/report"curl -L "https://api.core-tnn1.exptech.dev/api/v1/eq/report"curl -L "https://api.core-tyo1.exptech.dev/api/v1/eq/report"const res = await fetch("https://api.core.exptech.dev/api/v1/eq/report");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);const res = await fetch("https://api.core-tnn1.exptech.dev/api/v1/eq/report");if (!res.ok) throw new Error(`HTTP ${res.status}`);const data = await res.json();console.log(data);const res = await fetch("https://api.core-tyo1.exptech.dev/api/v1/eq/report");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.exptech.dev/api/v1/eq/report", timeout=10)res.raise_for_status()print(res.json())import requests
res = requests.get("https://api.core-tnn1.exptech.dev/api/v1/eq/report", timeout=10)res.raise_for_status()print(res.json())import requests
res = requests.get("https://api.core-tyo1.exptech.dev/api/v1/eq/report", timeout=10)res.raise_for_status()print(res.json())成功(沒有資料時為空陣列 [])
[ { "id": "CWA-EQ114000-2025-0829-100546", "no": "2025082910054600000", "lat": 22.86, "lon": 121.28, "depth": 16.9, "loc": "臺東縣政府東北方 17.5 公里 (位於臺東縣近海)", "mag": 4, "time": 1756433146000, "list": { "臺東縣": { "int": 2, "town": { "東河": { "lat": 22.97, "lon": 121.3, "int": 2 } } } } }]參數不是正規形式,導向正規網址
HTTP/1.1 302 FoundLocation: /api/v1/eq/reportIf-None-Match 與 ETag 相同,沒有內容沒有回應本文
伺服器錯誤
{ "error": "<錯誤訊息>"}試試看
與 v2 的差異:
| 欄位 | 類型 | 說明 |
|---|---|---|
[].id | string | 報告 ID,比 v2 多了 CWA-EQ 前綴,例如 CWA-EQ114000-2025-0829-100546。去掉前綴就是 v2 的 ID。 |
[].no | string | 氣象署的地震編號字串,前 14 碼是發震時間 YYYYMMDDHHMMSS(臺灣時間)。v2 沒有這個欄位。 |
[].list | object | 各縣市與測站震度,格式同 v2 單筆報告的 list。 |
其餘欄位(lat、lon、depth、loc、mag、time)與 v2 相同。v1 沒有 int、trem、md5。?limit=1 等於預設值,會 302 到沒有 query 的網址。
