本文へスキップ

気象庁の地震情報JSON(公式APIではない)の読み方:list.jsonの略語キー、震源の座標、同じ地震の複数報

SHAYOUWORLD 公開 約7分

要点

  1. 一覧は1本のURL。 https://www.jma.go.jp/bosai/quake/data/list.json をキーなしでGETすると、約1か月分の地震情報が新しい順に入っています。
  2. 同じ地震に複数の報がある。 震度速報、震源に関する情報、震源・震度情報が別々の件として並びます。地震ID eid でまとめます。
  3. 震源は1つの文字列。 cod の +35.7+140.7-50000/ は北緯35.7度、東経140.7度、深さ50kmです。
  4. ser は型が混ざる。 212件のうち184件は文字列("1"、"2")、28件は数値の 0 でした。並べ替えには使いません。
  5. 詳細JSONは配列とオブジェクトが混ざる。 地域が1つだけだとオブジェクト、複数だと配列で入ります。

最近の地震をプログラムやAIエージェントで扱うなら、list.json を取得し、地震ID eid ごとにまとめて、最新の報から震源と最大震度を取り出します。 気象庁ホームページの地震情報の画面が読み込むファイルで、API仕様書は見つかりませんでした。キー名は ttl、anm、cod、maxi のような略語で、その意味は値と画面のスクリプトから読むしかありません。

2026年10月20日に、Node.js(依存なし)とcurlから一覧を3回、詳細JSONを3件、地図ページを1回取得しました。一覧には2026年9月20日から10月20日までの212件が入っていました。天気予報と観測値は、天気予報JSONの使い方とアメダスの観測値JSONの使い方で扱っています。

list.json の形

一覧は配列で、rdt(発表時刻)の新しい順に並んでいました。HTTPの応答は Content-Type: application/json、Content-Encoding: br、Cache-Control: max-age=60 で、展開後は205,382バイトでした。先頭の1件です(int は抜粋)。

{
"ctt": "20261020055328", "eid": "20261020055029",
"rdt": "2026-10-20T05:53:00+09:00", "ttl": "震源・震度情報", "ift": "発表", "ser": "1",
"at": "2026-10-20T05:50:00+09:00", "anm": "釧路沖", "acd": "190",
"cod": "+42.4+144.7-30000/", "mag": "4.0", "maxi": "2",
"int": [ { "code": "01", "maxi": "2", "city": [ { "code": "0120600", "maxi": "2" }, ... ] } ],
"json": "20261020055328_20261020055029_VXSE5k_1.json",
"en_ttl": "Earthquake and Seismic Intensity Information", "en_anm": "Off the Coast of Kushiro"
}

212件すべてが同じ16個のキーを持っていました。値から読んだ対応です。

キー値の例読み方
eid20261020055029地震ID。同じ地震の報で共通
ttl震源・震度情報情報の種類
rdt2026-10-20T05:53:00+09:00発表時刻
ctt20261020055328作成時刻(秒まで、日本時間)
at2026-10-20T05:50:00+09:00地震の発生時刻
anm / acd釧路沖 / 190震央地名とそのコード
cod+42.4+144.7-30000/震源の緯度・経度・高さ(m)
mag4.0マグニチュード。文字列
maxi2最大震度。文字列
int都道府県と市町村の配列都道府県コード2桁、市町村コード7桁ごとの最大震度
ift / ser発表 / "1"発表の区分と番号。212件すべて「発表」
json..._VXSE5k_1.json詳細JSONのファイル名

情報の種類と、同じ地震の複数報

212件の ttl の内訳です。詳細JSONのファイル名の3番目の部分も、種類ごとに決まっていました。

ttl件数ファイル名の符号空の項目
震源・震度情報181VXSE5kなし
震度速報14VXSE51anm・cod・mag が空、int は都道府県だけ
震源に関する情報13VXSE52maxi が空、int が空配列
遠地地震に関する情報3VXSE5emaxi が空。cod に深さがない
南海トラフ地震関連解説情報1VYSE52cod・mag・maxi が空

気象庁の地震情報についてによると、震度速報は震度3以上で、地震発生約1分半後に震度3以上を観測した地域名(全国188地域)と揺れの検知時刻を速報します。震源に関する情報は震度3以上(津波警報等を発表した場合は発表しない)で、震源と規模を発表します。震源・震度情報は震度1以上などで、震源・規模・各地点の震度を発表します。

一覧の eid は183種類で、14の地震に複数の報がありました。2026年10月8日4時13分ころの千葉県北東部の地震では、次の順に並んでいます。

  1. 04:13
    地震の発生(at)
    千葉県北東部、M4.8、深さ約50km、最大震度4
  2. 04:15
    震度速報(VXSE51)
    maxi は 4。震源(anm・cod・mag)は空
  3. 04:16
    震源に関する情報(VXSE52)
    震源と M4.8 が入る。maxi は空
  4. 04:17
    震源・震度情報(VXSE5k、ser "1")
    震源と最大震度4、市町村ごとの震度がそろう
list.json(2026-10-20取得)の eid 20261008041355 の3件

報によって欠ける項目が違うので、最新の1件だけを見ると、震源か震度のどちらかが空になる時間帯があります。 震源は cod が入っている最新の報から、震度は maxi が入っている最新の報から取ります。

報が更新される例もありました。9月29日4時45分ころの茨城県南部の地震は、震度速報が4時46分と4時47分の2件、震源・震度情報が4時49分(ser が "1")と4時54分("2")の2件でした。2報目では神奈川県(int のコード14)の市町村が38から52に増えていました。国外の地震では、10月10日の中米の地震のマグニチュードが、1報目の8.0から2報目で7.6に変わっていました。

ser は並べ替えに使えません。 212件のうち、"1" が182件、"2" が2件の文字列で、震度速報などの28件は数値の 0 でした。同じ地震の報の順番は、rdt と ctt で決めます。

cod・maxi・mag の読み方

cod は、緯度・経度・高さを符号付きでつないだ文字列です。高さはメートルで、負の値が深さになります。

+42.4+144.7-30000/ -> 北緯42.4度、東経144.7度、深さ30km
+32.6+130.7+0/ -> 北緯32.6度、東経130.7度、深さ0km(212件中33件)
+07.5-080.8/ -> 北緯7.5度、西経80.8度、深さなし(国外の地震)

深さ0の件の詳細JSONも取得しましたが、Coordinate は同じ文字列だけで、説明の文はありませんでした。地図ページのスクリプトは、深さが5km未満なら「ごく浅い」、それ以外は「約○km」と表示していました。

maxi は文字列です。212件では "1"(126件)、"2"(41件)、"3"(20件)、"4"(8件)、空(17件)でした。地図ページのスクリプトは、ほかに次の値を扱っていました。

"5-" 震度5弱 "5+" 震度5強 "6-" 震度6弱 "6+" 震度6強 "7" 震度7
"5@" 震度5弱以上未入電

震度についてのとおり、震度は0から7までの10階級です。"5-" を数値に変換すると NaN になり、parseInt では5になって弱と強の区別が消えます。文字列のまま、対応表で順位を付けます。"5@" は、震度5弱以上と考えられるのに震度を入手できていない地点があることを表す値で、スクリプトの順位では震度4と5弱のあいだでした。

mag も文字列で、震度速報などの15件は空でした。地図ページのスクリプトは、「M8を超」を含む文字列を「M8超」、「不明」を含む文字列を「---」と表示する処理を持っていました。今回の212件には現れていませんが、数値に変換できない値として扱える形にしておきます。

詳細JSONは Control・Head・Body

json のファイル名を https://www.jma.go.jp/bosai/quake/data/ に付けると、詳細JSONが取れます。千葉県北東部の震源・震度情報(53,935バイト)と震度速報(1,996バイト)を取得しました。

震源・震度情報(VXSE5k)
震度速報(VXSE51)
Head.Title
震源・震度情報
震度速報
Head.Serial
"1"
null(一覧では数値の 0)
Body.Earthquake
発生時刻、震源(名前・コード・座標)、マグニチュード
なし
Body.Intensity
都道府県 → 地域 → 市町村 → 観測点(206地点)
都道府県 → 地域まで
Body.Comments
「この地震による津波の心配はありません。」など
「今後の情報に注意してください。」
eid 20261008041355 の詳細JSON(2026-10-20取得)

Control・Head・Body の3つに分かれた形で、XMLを変換したような構造です。変換の名残で、同じキーが、要素が1つならオブジェクト、2つ以上なら配列で入っていました。 見出しの Head.Headline.Information[].Item[].Areas.Area は、震度4の千葉県北東部では1件のオブジェクト、震度3の茨城県南部と千葉県北西部では2件の配列でした。どちらでも配列として扱う関数を挟みます。

観測点の名前は、206地点のうち171地点の末尾に「*」が付いていました。同じJSONの Body.Comments.VarComment に「*印は気象庁以外の震度観測点についての情報です。」とあり、英語文は地方公共団体または防災科学技術研究所の観測点としています。名前を検索キーにするときは「*」を外して比べます。

// quake-detail.mjs — 保存した詳細JSONを要約する(通信しない)
import { readFile } from 'node:fs/promises';
// XMLから変換されたJSONは、要素が1つだとオブジェクト、2つ以上だと配列になる箇所がある
const arr = (v) => (v == null ? [] : Array.isArray(v) ? v : [v]);
const INT_RANK = ['1', '2', '3', '4', '5@', '5-', '5+', '6-', '6+', '7'];
export function summarizeDetail(d) {
const eq = d.Body.Earthquake;
const byInt = {};
let stations = 0, otherAgency = 0;
for (const pref of arr(d.Body.Intensity?.Observation?.Pref)) {
for (const area of arr(pref.Area)) {
for (const city of arr(area.City)) {
(byInt[city.MaxInt] ??= []).push(city.Name);
for (const st of arr(city.IntensityStation)) {
stations++;
if (st.Name.endsWith('*')) otherAgency++;
}
}
}
}
// 見出しの地域リストは Area がオブジェクトの場合と配列の場合がある
const headline = arr(d.Head.Headline.Information).flatMap((info) => arr(info.Item).map((item) => ({ kind: item.Kind.Name, areas: arr(item.Areas.Area).map((a) => a.Name) })));
return {
title: d.Head.Title, reportDatetime: d.Head.ReportDateTime, eventId: d.Head.EventID, serial: d.Head.Serial,
originTime: eq?.OriginTime, hypocenter: eq?.Hypocenter.Area.Name, coordinate: eq?.Hypocenter.Area.Coordinate, magnitude: eq?.Magnitude,
maxInt: d.Body.Intensity?.Observation?.MaxInt,
// 震度3以上は市町村名、それ未満は数だけ
citiesByMaxInt: Object.fromEntries(Object.entries(byInt).map(([k, v]) => [k, INT_RANK.indexOf(k) >= INT_RANK.indexOf('3') ? v : `${v.length}市町村`])),
stations, otherAgencyStations: otherAgency,
comments: [d.Body.Comments?.ForecastComment?.Text, d.Body.Comments?.VarComment?.Text].filter(Boolean),
headlineFirst: headline.slice(0, 2),
};
}
const d = JSON.parse(await readFile(process.argv[2], 'utf8'));
console.log(JSON.stringify(summarizeDetail(d), null, 2));
$ node quake-detail.mjs 20261008041755_20261008041355_VXSE5k_1.json
"title": "震源・震度情報", "reportDatetime": "2026-10-08T04:17:00+09:00", "serial": "1",
"hypocenter": "千葉県北東部", "coordinate": "+35.7+140.7-50000/", "magnitude": "4.8", "maxInt": "4",
"citiesByMaxInt": {
"1": "85市町村", "2": "32市町村",
"3": ["匝瑳市", "香取市", "山武市", "多古町", "芝山町", "成田市", "潮来市", "稲敷市"],
"4": ["旭市"] },
"stations": 206, "otherAgencyStations": 171,
"comments": ["この地震による津波の心配はありません。", "*印は気象庁以外の震度観測点についての情報です。"],
"headlineFirst": [ { "kind": "震度4", "areas": ["千葉県北東部"] }, { "kind": "震度3", "areas": ["茨城県南部", "千葉県北西部"] } ]

Node.jsで地震ごとにまとめる

一覧を取得し、国内の地震の3種類だけを eid でまとめます。最大震度が指定以上の地震について、震源と最大震度を最新の報から取り出します。

// jma-quake.mjs — 依存なし(Node.js 18 以降の組み込み fetch)
// 使い方: node jma-quake.mjs 3 (最大震度3以上の地震を、地震ごとに1件へまとめて表示)
const UA = 'jma-quake-example/0.1 (+https://codeagent.jp/)';
const BASE = 'https://www.jma.go.jp/bosai/quake/data';
// 画面のスクリプトと同じ並び。"5@" は「震度5弱以上未入電」
const INT_LABEL = { '1': '震度1', '2': '震度2', '3': '震度3', '4': '震度4', '5-': '震度5弱', '5+': '震度5強', '6-': '震度6弱', '6+': '震度6強', '7': '震度7', '5@': '震度5弱以上未入電' };
const INT_RANK = ['1', '2', '3', '4', '5@', '5-', '5+', '6-', '6+', '7'];
const KINDS = ['震度速報', '震源に関する情報', '震源・震度情報']; // 国内の地震の3種類だけを扱う
async function getJson(url) {
const res = await fetch(url, { headers: { 'User-Agent': UA } });
const type = res.headers.get('content-type') ?? '';
if (!res.ok || !type.includes('json')) throw new Error(`取得失敗: ${url} -> HTTP ${res.status} (${type})`);
return res.json();
}
// "+35.7+140.7-50000/" → 緯度・経度・深さ(km)。深さが無い形もある
function parseCod(cod) {
const m = /^([+-]\d+(?:\.\d+)?)([+-]\d+(?:\.\d+)?)([+-]\d+)?\/$/.exec(cod ?? '');
if (!m) return null;
const depthKm = m[3] === undefined ? null : -Number(m[3]) / 1000;
return { lat: Number(m[1]), lon: Number(m[2]), depthKm, depthLabel: depthKm === null ? null : depthKm < 5 ? 'ごく浅い' : `約${depthKm}km` };
}
const min = process.argv[2] ?? '3';
const list = await getJson(`${BASE}/list.json`);
const retrievedAt = new Date().toISOString();
// eid(地震ID)でまとめる。同じ地震に震度速報・震源・震源震度の複数報がある
const events = new Map();
for (const r of list) {
if (!KINDS.includes(r.ttl)) continue;
const e = events.get(r.eid) ?? { eid: r.eid, reports: [] };
e.reports.push(r);
events.set(r.eid, e);
}
const out = [];
for (const e of events.values()) {
// 新しい報を先に。rdt が同じなら作成時刻 ctt で比べる。ser は文字列と数値が混ざるので使わない
e.reports.sort((a, b) => (b.rdt + b.ctt).localeCompare(a.rdt + a.ctt));
const withHypo = e.reports.find((r) => r.cod);
const withInt = e.reports.find((r) => r.maxi);
if (!withInt || INT_RANK.indexOf(withInt.maxi) < INT_RANK.indexOf(min)) continue;
const mag = withHypo?.mag ?? '';
out.push({
eid: e.eid,
originTime: e.reports[0].at,
area: withHypo?.anm || null, // 震度速報しか出ていなければ震源は未発表
hypocenter: parseCod(withHypo?.cod),
magnitude: /^\d+(\.\d+)?$/.test(mag) ? Number(mag) : null,
magnitudeText: mag || null, // "M8を超える巨大地震" のような文字列もありうる
maxIntensity: INT_LABEL[withInt.maxi] ?? withInt.maxi,
latestReport: { title: e.reports[0].ttl, reportDatetime: e.reports[0].rdt },
reportTitles: e.reports.map((r) => `${r.ttl}(${r.rdt.slice(11, 16)})`),
detailUrl: `${BASE}/${(e.reports.find((r) => r.ttl === '震源・震度情報') ?? e.reports[0]).json}`,
});
}
console.log(JSON.stringify({
listEntries: list.length,
events: out.length,
items: out.slice(0, 5),
provenance: {
source: `${BASE}/list.json`,
retrievedAt,
attribution: '出典:気象庁ホームページ(https://www.jma.go.jp/bosai/map.html#contents=earthquake_map)を加工して作成',
warnings: ['気象庁ホームページが内部で使うJSON。API仕様としては公開されておらず、予告なく変わりうる'],
},
}, null, 2));

10時35分に実行した結果です(5件のうち2件目を抜粋)。

$ node jma-quake.mjs 3
"listEntries": 212, "events": 13,
{ "eid": "20261008041355", "originTime": "2026-10-08T04:13:00+09:00", "area": "千葉県北東部",
"hypocenter": { "lat": 35.7, "lon": 140.7, "depthKm": 50, "depthLabel": "約50km" },
"magnitude": 4.8, "magnitudeText": "4.8", "maxIntensity": "震度4",
"latestReport": { "title": "震源・震度情報", "reportDatetime": "2026-10-08T04:17:00+09:00" },
"reportTitles": ["震源・震度情報(04:17)", "震源に関する情報(04:16)", "震度速報(04:15)"],
"detailUrl": "https://www.jma.go.jp/bosai/quake/data/20261008041755_20261008041355_VXSE5k_1.json" }
"provenance": { "source": "https://www.jma.go.jp/bosai/quake/data/list.json", "retrievedAt": "2026-10-20T01:35:32.838Z", ... }

約1か月分の212件が、最大震度3以上の13の地震にまとまりました。震源・震度情報がまだ出ていない地震では、area と hypocenter が null のまま、震度だけを返します。

AIエージェント・MCPツールにするときの設計

  1. 地震ごとにまとめてから渡す。 一覧をそのまま渡すと、同じ地震の3報を3つの地震と数えます。eid でまとめ、どの報から取った値かを latestReport と reportTitles で残します。
  2. 値の型を固定する。 maxi は文字列のまま対応表で順位を付け、mag は数値と元の文字列の両方を返します。ser は使いません。
  3. 発表時刻と出典を返す。 地震の発生時刻(at)と発表時刻(rdt)を分け、取得元URLと取得日時を付けます。型はMCPの出典情報を欠落させないoutputSchema設計に合わせられます。
  4. 取得の間隔はサーバー側で決める。 一覧は max-age=60 の間は取り直しません。詳細JSONは必要な地震だけ取得します。考え方は公共データAPIをMCP化する設計パターンにあります。
  5. 発表された内容の範囲だけを答えさせる。 余震の見通しや被害の推測を作らせません。気象庁ホームページについてのページは、気象業務法第17条(予報業務の許可)と第23条(警報の制限)による制約に注意を促しています。
- 地震の回答は get_recent_quakes の結果だけを根拠にし、発生時刻・発表時刻・出典を併記する
- 震源が null の地震は「震源は未発表」と書き、震度から震源を推測しない
- 「*」の付いた観測点は気象庁以外の震度計であることを、地点名を出すときに残す
- 今後の揺れや被害の見通しを作らない。行動の判断は気象庁・自治体の発表を確認するよう返す
- 出典は「出典:気象庁ホームページ(URL)を加工して作成」の形で残す

まとめ

  • 一覧は quake/data/list.json。キー不要でGETのみ。2026年10月20日は約1か月分の212件
  • 同じ地震に震度速報・震源に関する情報・震源・震度情報が並ぶ。eid でまとめ、震源と震度は別々の報から取る
  • cod は緯度・経度・高さ(m)。深さ0は33件、画面は5km未満を「ごく浅い」と表示
  • maxi・mag は文字列。ser は文字列と数値が混ざるので並べ替えに使わない
  • 詳細JSONは Control・Head・Body。Area は1件ならオブジェクト、複数なら配列

ほかの公共データとの使い分けは公共データAPIのガイドにあります。

この記事の情報・検証メモ
Tags
公開日
情報確認
参考リンク
4件
更新性
定期更新
更新管理

仕様・料金・提供範囲が変わりやすいテーマは、公開日・更新日・情報確認日を分けて管理します。 導入前には必ず記事末尾の一次情報と公式ドキュメントで最新状況を確認してください。

検証メモ
Node.js 24.8.0(組み込み fetch、依存なし)、curl(Git Bash) 気象庁ホームページの地震情報JSON・地図ページ 取得日 2026-10-20(計7リクエスト)
図解を保存・共有

記事の要点を1枚にまとめました。画像は新しいタブで開いて保存できます。

気象庁の地震情報JSON(公式APIではない)の読み方:list.jsonの略語キー、震源の座標、同じ地震の複数報 同じ地震に何報も出る。eid でまとめ、最新の報の震源と震度を出典付きで返す list.json の形:約1か月分の配列。2026-10-20は212件。ttl は情報の種類、maxi は最大震度、cod は震源。ser は "1" と 0 のように文字列と数値が混ざる。 値の読み方:cod "+35.7+140.7-50000/" は北緯・東経・深さ50km。深さ5km未満は、画面では「ごく浅い」。震度速報には震源、震源に関する情報には震度がない。 詳細JSON:Control・Head・Body の3つに分かれる。Area は1件ならオブジェクト、複数なら配列。*の付いた観測点は気象庁以外の震度計。
気象庁の地震情報JSON(公式APIではない)の読み方:list.jsonの略語キー、震源の座標、同じ地震の複数報 記事の要約 2026.10.20 実装・公開事例
Primary sources

一次情報・参考リンク

About the author
SHAYOUWORLD

日本の公共データAPIを使うMCPサーバーを作って公開し、ローカルLLMを自分のGPUで測った記録を、一次情報・検証ログ・失敗例とあわせて整理します。