ネットに出ている J-Quants のサンプルコードをそのまま動かして、認証で止まる・403 が返る・キーエラーで落ちる——これは書いた人が間違えたのではなく、API が作り替わったためです。
- V1 は 2026年6月1日に終了しました。いま動くのは V2 だけです
- 認証がトークン方式から APIキー方式に変わりました
- エンドポイントが全部変わりました(対応表を載せています)
- レスポンスのカラム名が短縮形になりました。Close が
Cです。ここが一番静かに壊れます - Premium の取得期間が「無制限」から「過去20年」に縮みました
まず結論:V1 はもう存在しません
J-Quants API は V1 から V2 へ移行し、旧バージョンの V1 は 2026年6月1日に終了しました。2025年12月22日以降に登録した人は、はじめから V2 しか使えません。
つまり、2025年までに書かれた解説記事・サンプルコード・ライブラリの多くは、そのままでは動きません。検索で上位に出てくるものほど古いことがあるので、まずここを疑ってください。
この記事は公式ドキュメントの内容を整理したものです。実際に叩いて測った話(1リクエストあたりの速度、429がどのくらいで飛んでくるか、ティックCSVの実サイズなど)は、別の記事で出します。どこまでが仕様の話で、どこからが実測かは、記事ごとにはっきり分けます。
変わったところ(5つ+1)
1. 認証:トークン方式 → APIキー方式
V1 では、メールアドレスとパスワードでリフレッシュトークンを取り、それで ID トークンを取り、ID トークンを Authorization: Bearer に載せる——という3段構えでした。V2 ではこれが全部なくなります。
ダッシュボードで発行した APIキーを x-api-key ヘッダーに入れるだけです。APIキー自体に有効期限はありません(再発行と削除はできます)。トークンの期限切れを気にしてリフレッシュ処理を書いていた部分は、まるごと消せます。
# V1 のコード(もう動かない)
import requests
# 1. メールアドレスとパスワードでリフレッシュトークンを取る
r = requests.post(
"https://api.jquants.com/v1/token/auth_user",
json={"mailaddress": MAIL, "password": PASS},
)
refresh_token = r.json()["refreshToken"]
# 2. リフレッシュトークンから ID トークンを取る
r = requests.post(
"https://api.jquants.com/v1/token/auth_refresh",
params={"refreshtoken": refresh_token},
)
id_token = r.json()["idToken"]
# 3. ID トークンを Authorization ヘッダーに載せて叩く
r = requests.get(
"https://api.jquants.com/v1/prices/daily_quotes",
params={"code": "8697", "date": "2026-09-18"},
headers={"Authorization": f"Bearer {id_token}"},
)
quotes = r.json()["daily_quotes"]
print(quotes[0]["Close"])# V2 のコード
import requests
API_KEY = "..." # ダッシュボードの [API Keys] で発行する
r = requests.get(
"https://api.jquants.com/v2/equities/bars/daily",
params={"code": "8697", "date": "2026-09-18"},
headers={"x-api-key": API_KEY},
)
r.raise_for_status()
rows = r.json()["data"] # V1 の "daily_quotes" ではなく "data"
print(rows[0]["C"]) # V1 の "Close" ではなく "C" 2. エンドポイントが全部変わった
パスの付け方が「データの種類ごとの階層」に整理され直しました。対応表は次のとおりです。
| データ | V1 | V2 |
|---|---|---|
| トークン発行 | /v1/token/auth_user | 廃止(APIキーを使う) |
| トークンリフレッシュ | /v1/token/auth_refresh | 廃止(APIキーを使う) |
| 株価四本値 | /v1/prices/daily_quotes | /v2/equities/bars/daily |
| 前場四本値 | /v1/prices/prices_am | /v2/equities/bars/daily/am |
| 上場銘柄一覧 | /v1/listed/info | /v2/equities/master |
| 決算発表予定日 | /v1/fins/announcement | /v2/equities/earnings-calendar |
| 投資部門別情報 | /v1/markets/trades_spec | /v2/equities/investor-types |
| 財務情報 | /v1/fins/statements | /v2/fins/summary |
| 財務諸表(BS/PL/CF) | /v1/fins/fs_details | /v2/fins/details |
| 配当金情報 | /v1/fins/dividend | /v2/fins/dividend |
| 取引カレンダー | /v1/markets/trading_calendar | /v2/markets/calendar |
| 売買内訳データ | /v1/markets/breakdown | /v2/markets/breakdown |
| 信用取引週末残高 | /v1/markets/weekly_margin_interest | /v2/markets/margin-interest |
| 日々公表信用取引残高 | /v1/markets/daily_margin_interest | /v2/markets/margin-alert |
| 業種別空売り比率 | /v1/markets/short_selling | /v2/markets/short-ratio |
| 空売り残高報告 | /v1/markets/short_selling_positions | /v2/markets/short-sale-report |
| 指数四本値 | /v1/indices | /v2/indices/bars/daily |
| TOPIX指数四本値 | /v1/indices/topix | /v2/indices/bars/daily/topix |
| 先物四本値 | /v1/derivatives/futures | /v2/derivatives/bars/daily/futures |
| オプション四本値 | /v1/derivatives/options | /v2/derivatives/bars/daily/options |
| 日経225オプション四本値 | /v1/option/index_option | /v2/derivatives/bars/daily/options/225 |
見てのとおり、機械的に置換できるものはほとんどありません。/v1/ を /v2/ に変えるだけでは動きません。
3. レスポンスが data キーに統一された
V1 はエンドポイントごとに入れ物の名前が違いました(daily_quotes、info、statements など)。V2 は原則としてすべて data の配列で返ってきます。
{
"data": [
{ ... },
{ ... }
],
"pagination_key": "..."
}該当データが0件のときもエラーにはならず、200 で {"data": []} が返ります。pagination_key は付きません。
4. カラム名が短縮形になった(ここが一番危ない)
認証やエンドポイントの変更は、動かないのですぐ気づきます。怖いのはこちらです。
| 項目 | V1 | V2 |
|---|---|---|
| 始値 | Open | O |
| 高値 | High | H |
| 安値 | Low | L |
| 終値 | Close | C |
| 出来高 | Volume | Vo |
| 売買代金 | TurnoverValue | Va |
| 調整後始値 | AdjustmentOpen | AdjO |
| 調整後高値 | AdjustmentHigh | AdjH |
| 調整後安値 | AdjustmentLow | AdjL |
| 調整後終値 | AdjustmentClose | AdjC |
| 調整後出来高 | AdjustmentVolume | AdjVo |
| 調整係数 | AdjustmentFactor | AdjFactor |
| 日付 | Date | Date(変わらず) |
| 銘柄コード | Code | Code(変わらず) |
これが静かに壊れる理由。たとえば row.get("Close") と書いていたコードは、V2 では例外を出さずに None を返します。None のまま計算に流れ込めば、「バックテストは通ったのに成績がおかしい」という形で後から出てきます。移行のときは .get() ではなく [] で取り、キーが無ければその場で落とすほうが安全です。
5. レートリミットが新設された
V1 には明示のレートリミットがありませんでした。V2 ではプランごとに上限が決まっています。
| プラン | 上限(リクエスト/分) |
|---|---|
| Free | 5 |
| Light | 60 |
| Standard | 120 |
| Premium | 500 |
加えて、財務情報(/v2/fins/summary)と財務諸表(/v2/fins/details)は、プランに関係なく専用枠で 60/分。分足・ティックのアドオンも専用枠で 60/分です。
上限を超えると 429 が返ります。Retry-After ヘッダーは付きません。判定は1分のスライディングウィンドウで、429 になったリクエストも回数に数えられるため、待たずに投げ直すと制限が解けるまでの時間が延びます。大幅に超過し続けると、5分程度アクセスが完全に遮断されることがあります。
import time
import requests
def get_with_retry(url, params, headers, tries=5):
for i in range(tries):
r = requests.get(url, params=params, headers=headers, timeout=60)
if r.status_code == 429:
# Retry-After は付かない。1分のスライディングウィンドウなので
# 「すぐ投げ直さず、余裕をみて待つ」以外に手はない
time.sleep(90)
continue
if r.status_code in (500, 502, 503, 504):
time.sleep(5 * (i + 1))
continue
r.raise_for_status()
return r.json()
raise RuntimeError(f"{tries} 回試しても取れなかった: {url} {params}")おまけ:Premium の取得期間が縮んだ
見落とされがちですが、Premium プランの期間制限が「無制限」から「過去20年分」に変わりました。20年より前まで遡る検証を組んでいた場合は、前提が変わります。
逆に緩くなった点もあり、上場銘柄一覧の貸借信用区分は、V1 では Standard 以上だったものが V2 では全プランで取れるようになりました。
ページングの書き方
レスポンスが大きいと pagination_key が付いて返ってきます。付かなくなるまで繰り返すのが全件取得の作法です。総件数を返す項目はありません。
import requests
HEADERS = {"x-api-key": API_KEY}
URL = "https://api.jquants.com/v2/equities/bars/daily"
def fetch_all(**params):
out = []
while True:
r = requests.get(URL, params=params, headers=HEADERS)
r.raise_for_status()
body = r.json()
out += body["data"]
key = body.get("pagination_key")
if not key:
return out
params["pagination_key"] = key # 他の条件は変えないこと- 分割が起きるのは、レスポンスが 5,000,000 バイト相当に達したとき
- 1回あたりの件数は内部処理で変動し、非公開・保証対象外
pagination_keyの値は毎回変わる- 繰り返しの途中でデータが更新された場合、取得結果全体の一貫性は保証されない
403 が返ったときの読み分け
V2 の 403 は複数の原因で返ります。メッセージを見ないと切り分けられません。
| メッセージ/状況 | 原因 |
|---|---|
The incoming api key is invalid or expired. | APIキーの値そのものが認識できない |
| メッセージなしで 403 | 契約プランに含まれていないデータ・エンドポイントを叩いている |
| 特定のエンドポイントだけ 403 | URL か HTTP メソッドの誤り。V1 のパスを叩いている場合もここ |
V1 のパスを叩くと 404 ではなく 403 が返ることがあります。「権限の問題かと思ってプランを上げたが直らない」という遠回りをしやすいので、まず自分が叩いている URL が /v2/ かを確かめてください。
移行チェックリスト
- ダッシュボードの [API Keys] でAPIキーを発行する
auth_user/auth_refreshを呼んでいる箇所をすべて削除するAuthorization: Bearerをx-api-keyに置き換える- エンドポイントを対応表で1つずつ書き換える(機械置換はできない)
- レスポンスの取り出しを
dataに統一する - カラム名を短縮形に直す。
.get()ではなく[]で取って、抜けていればその場で落とすようにする - 429 を待って再開する処理を入れる(
Retry-Afterは来ない) pagination_keyが付かなくなるまで繰り返すようにする- Premium を使っていて20年より前を見ていた場合は、検証期間の前提を見直す
Windows で叩くときの細かい注意
公式ドキュメントにも注記がありますが、PowerShell では2つ引っかかります。
- シングルクォートの中で変数が展開されません。ヘッダーはダブルクォートで書きます(
-H "x-api-key: $key") curlが別コマンドの別名になっていることがあります。curl.exeと明示してください
curl.exe -G "https://api.jquants.com/v2/equities/bars/daily" `
-H "x-api-key: $key" `
-d code=8697 `
-d date=2026-09-18まとめ
V1 から V2 への移行は、「認証を差し替えれば済む」という規模ではありません。エンドポイント・レスポンス構造・カラム名の3つが同時に変わっているので、データを取る層はほぼ書き直しになります。
そのうえで、いちばん怖いのはカラム名です。認証もパスも直して「動いた」と思ったあとに、Close が取れていなかったことに気づく——という順番になりがちだからです。検証の数字がおかしいと感じたら、まずそこを見てください。
この記事の出どころ
- 情報源:J-Quants API 公式ドキュメント (V1 API から V2 API への変更点/クイックスタート/レートリミットについて/レスポンスステータス/レスポンスのページングについて)
- 参照日:2026年9月20日
- この記事の性格:公式ドキュメントの整理です。実際に叩いて測った数字は含みません
- 動作確認:未実施。実測にもとづく記事は別途公開します