楽天APIが2026年に大改変。エラーメッセージが嘘をついていた

エラーは嘘をついていた — 犯人は Origin ヘッダー(楽天API 2026年改変)
mausu110

ブログの商品カードを自動化しようとしたら、3連続で門前払いされた

こんにちは、へっぽこITエンジニアのやまさんです。

このブログ、記事の中でときどき「使った道具」を紹介しています。あれを毎回手作業でリンク化するのが地味にしんどい。商品名・価格・画像・アフィリエイトリンクを一気に取ってきて、商品カードを自動生成できたらどんなに楽か……ということで、楽天商品検索APIを叩くスクリプトを書き始めました。

「まあ、公開APIだし30分もあれば動くでしょ」と思っていました。甘かったです。

結果として、動き始めるまでに3段階でつまずきました。しかも最後の3つ目は、エラーメッセージが指している名前と、実際に検証されているものが食い違っているという、なかなか意地の悪いやつでした。ネットで見つかる解説記事はどれも以前の仕様のままで、答えが書いてある場所がどこにもありません。

この記事を読み終わるころには、2026年時点の楽天商品検索APIを叩くための「新しいエンドポイント・accessKey・Origin ヘッダー」の3点セットが揃って、コピペで動く最小コードが手に入ります。同じ403で消耗している人の時間を、まるっと節約できたら嬉しいです。

先に結論だけ言っておきます。

403 の HTTP_REFERRER_MISSING は、Referer を送っても直りません。必要なのは Origin ヘッダーです。

今回使ったもの

道具というほど大げさなものは使っていません。むしろ「情報」が今回の主役でした。

  • 楽天ウェブサービス(楽天商品検索API) … 商品名・価格・画像URL・アフィリエイトリンクをまとめて取得できる公式API。無料で使えます。アプリIDや accessKey は Rakuten Developers の管理画面から発行します
  • Python + requests … 今回のような「ヘッダーを1つずつ変えて総当たりする」作業に、これ以上向いた組み合わせはありません
  • 自分のブログのドメイン … 後述しますが、これがないと話が始まりません。API側の「許可されたウェブサイト」に登録したドメインが、そのまま認証の材料になります

有料のものは1つもありません。かかったのは、半日ぶんの気力だけです。

動くまでに3段階でつまずいた

つまずき1: 新しいアプリIDが、昔のエンドポイントに弾かれる

まずは素直に、ネットでよく見かけるエンドポイントに投げてみます。新規に発行したアプリIDは、UUID形式(df10456b-bb97-... みたいなやつ)でした。

GET https://app.rakuten.co.jp/services/api/IchibaItem/Search/20220601
  ?applicationId=df10456b-bb97-...

返ってきたのがこれ。

400 {"error_description":"specify valid applicationId","error":"wrong_parameter"}

「有効なアプリIDを指定してください」。 いやいや、たった今コピペしてきたばかりなんですが……。

ここで15分くらい、管理画面とターミナルを行ったり来たりしました。スペースが混じってないか、改行が入ってないか。全部シロ。

正解は、アプリIDではなくエンドポイントのほうが変わっていた、でした。

新: https://openapi.rakuten.co.jp/ichibams/api/IchibaItem/Search/20260701

ドメインからして別物(app.rakuten.co.jpopenapi.rakuten.co.jp)です。新しく発行したアプリIDは新エンドポイント向けのもので、それを旧エンドポイントに投げていたから「そんなIDは知らない」と言われていた、というわけです。

エラーメッセージが「applicationIdが不正」と言っているので、犯人はIDだと思い込んでしまう。この記事、最初から最後までこの構図です。

つまずき2: accessKey という新顔が要求される

エンドポイントを新しいものに差し替えて、再挑戦。

400 {"errors":{"errorCode":400,
     "errorMessage":"accessKey must be present as a query parameter or in the header"}}

今度は素直なメッセージです。applicationId に加えて accessKey が必要になっていました。pk_ で始まる文字列で、Rakuten Developers の「あなたのアプリ」の画面から取得できます。

これはメッセージのとおりに追加すれば通るので、実質ノーダメージ。むしろ「ちゃんと理由を教えてくれるエラー、ありがたいな」と思ったのを覚えています。このあと、その優しさが恋しくなります。

本題。犯人は Referer ではなく Origin だった

accessKey を付けて、いよいよ通るはず。そう思って実行した結果がこれです。

403 {"errors":{"errorCode":403,
     "errorMessage":"REQUEST_CONTEXT_BODY_HTTP_REFERRER_MISSING"}}

HTTP_REFERRER_MISSING「リファラが無いよ」と、これ以上ないくらいはっきり書いてあります。じゃあ送りましょう。

headers = {"accessKey": KEY, "Referer": "https://yamasun-diy.com/"}
→ 403 REQUEST_CONTEXT_BODY_HTTP_REFERRER_MISSING

変わりません。

ここからが長かった。末尾のスラッシュを外す、http にしてみる、大文字小文字を変える。全部403。ヘッダーじゃなくてクエリパラメータなのかもしれないと思い、httpReferrerhttpRefererrequestContextBody と、思いつく名前を片っ端から試しました。

全部403。 メッセージの文字列すら1文字も変わりません。

正直このあたりで「アプリの登録内容がそもそも間違っているのでは」と疑い始めていました。でもその前に、もう1つだけ候補が残っていたんです。「どこから来たか」を伝えるヘッダーは、Referer だけじゃない。

headers = {"accessKey": KEY, "Origin": "https://yamasun-diy.com"}
→ 200 OK  ✅

通りました。

念のため、ヘッダーの組み合わせを変えて切り分けた結果がこちらです。

送ったヘッダー結果
Referer のみ❌ 403 ..._HTTP_REFERRER_MISSING
Origin のみ✅ 200
両方✅ 200
Referer と Origin の切り分け結果
Referer と Origin の切り分け結果

はっきりしました。Referer は、あってもなくても結果に一切影響しません。 検証されているのは Origin ただ1つです。にもかかわらず、エラーメッセージは HTTP_REFERRER_MISSING と名乗る。

RefererOrigin は、どちらも「このリクエストはどこから来たか」を伝えるヘッダーという意味では親戚です。ざっくり言えば、Referer が「このページから飛んできました」とURLまるごと伝えるのに対し、Origin は「このサイトから来ました」とドメインだけを伝える、ブラウザのCORS(別ドメインへのアクセス制御)で使われるほうの子。似ているけれど別物で、今回検証されていたのは後者だけでした。

新しいAPIがブラウザからの利用を前提に設計されると、こういうズレが生まれやすいのだと思います。そして、「Refererを送っても403が直らない」という報告がネット上に複数転がっているのは、おそらく全員がこのエラーメッセージに素直に誘導されているからでしょう。私もその一人でした。

コピペで動く最小コード

ここまでの3点セットを全部入れると、こうなります。

import requests

URL = "https://openapi.rakuten.co.jp/ichibams/api/IchibaItem/Search/20260701"

r = requests.get(
    URL,
    params={
        "applicationId": APP_ID,        # UUID形式
        "affiliateId": AFFILIATE_ID,    # xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx
        "keyword": "エルゴトロン LX モニターアーム",
        "hits": 3,
        "format": "json",
    },
    headers={
        "accessKey": ACCESS_KEY,                 # pk_ で始まる
        "Origin": "https://yamasun-diy.com",     # ★これが必須
    },
    timeout=30,
)

実際に返ってきたものがこちら。

ヒット数: 652
- 【モニターアーム】エルゴトロン LX デスクマウント マットブラック 45-241-22
  価格: 18,200円 / 店舗: エルゴトロン 楽天市場店
  アフィリエイトURL: https://hb.afl.rakuten.co.jp/hgc/...
  画像: https://thumbnail.image.rakuten.co.jp/@0_mall/ergotron/...

商品名・価格・店舗名・画像URL・アフィリエイトリンクが、1回のリクエストで全部揃います。 記事に商品を載せるのに必要な情報は、これで全部そろいました。半日かけただけの価値はありました。

アプリ登録でハマりやすいポイント

コードより手前、管理画面での登録にも小さな地雷があります。

  • アプリケーション名にハイフンが使えません。 yamasun-diy で登録しようとしたら「特殊文字を含めることはできません」で弾かれました。yamasundiy のように詰めれば通ります
  • 「許可されたウェブサイト」に自分のドメインを登録します。 ここに登録したドメインと、リクエストで送る Origin ヘッダーが一致している必要があります。逆に言うと、Origin だけ直しても登録側が空なら通りません
  • APIアクセススコープは「楽天市場API」だけで足ります。 迷って全部チェックする必要はありません
  • QPS(1秒あたりのリクエスト数)は 1 で十分でした。 記事1本あたり数回しか呼ばないので、上限を上げる必要はありませんでした

なお、こうした設定項目や上限値は時期・アカウントによって変わります。最新の値は必ず Rakuten Developers の管理画面とドキュメントでご確認ください。この記事の内容は2026年8月15日時点の実測です。

つまずいたポイントと、そこから得た教訓

エラーメッセージを信じすぎない

今回の3つのつまずきのうち、2つはエラーメッセージが原因を正しく指していませんでした。

  • 「applicationIdが不正」→ 実際はエンドポイントが古い
  • 「HTTP_REFERRERが無い」→ 実際に見ているのは Origin

エラーメッセージは開発者が書いた文字列であって、その時点の実装を正確に反映しているとは限りません。特にAPIの仕様が大きく変わった直後は、メッセージだけ昔の名前で取り残されていることがあります。「言われたとおりに直したのに変わらない」が2回続いたら、メッセージ自体を疑うタイミングです。

総当たりは、恥ずかしい手段ではなく有効な手段

今回、最終的に正解にたどり着いたのは「ヘッダーとパラメータの候補を6通り、機械的に全部試した」からです。スマートな推理ではありません。

でも、ドキュメントに書かれていないことは、試すしかないんですよね。requests で書いたループを回して、返ってきたステータスコードを並べる。それだけで表が1枚できて、「Referer は関係ない」という事実がはっきりしました。悩んでいる時間より、試す時間のほうが安いです。

古い記事を鵜呑みにしない

楽天商品検索APIの解説記事はネット上に山ほどあります。ただ、その大半は旧エンドポイント・アプリIDのみの時代のもので、今のまま真似しても1行目で400が返ります。 私も最初の30分はそれで溶かしました。日付が入ったエンドポイント(/20220601/20260701)を見比べるのが、いちばん手っ取り早い鮮度チェックかもしれません。

まとめ

半日かけて分かったことを3行にすると、こうなります。

  1. エンドポイントは https://openapi.rakuten.co.jp/ichibams/api/IchibaItem/Search/20260701
  2. applicationId に加えて accessKeypk_ 始まり)が要る
  3. 403 HTTP_REFERRER_MISSING の正解は Origin ヘッダーReferer は無関係)

たった3行です。でもこの3行がどこにも書かれていなかったので、この記事を書きました。同じところで止まっている人に届いたら本望です。

それにしても、RefererOrigin。この2つのヘッダーの名前を、今日ほどまじまじと見比べた日はありませんでした。

ABOUT ME
やまさん
やまさん
へっぽこITエンジニア
ねずみさんを愛するインフラエンジニア。 とにかく最新が好きで、ココロオドル体験を日夜求め続けています! 直近だとドローンにハートを撃ち抜かれてます。 空を自由に飛びたいな♪
記事URLをコピーしました