PA-API v5が提供終了らしいのでCreators APIに乗り換える

以前にiframeを利用した表示が終了した際に、PA-APIが移行先として示されていたので、PA-APIに移行しました。その時の記事がこちらです。

2024年頭に作業したようなので今までの期間がわずか2年ちょっと。そこでなんとこんなメールが来ました。最初はOffers V1、つまり、APIリクエスト内にあったOffersの項目がなくなるよという話で、Creators APIに乗り換えてもいいよという感じのスタンスだったのが2025年末ぐらいの話です。そして2026年の4月頭に一通のメールが…

【重要】PA-APIの廃止およびCreators APIへの切り替えのご案内

PA-API v5エンドポイントは、2026年5月15日をもってサービスを終了します。5月15日までにCreators APIへ移行をお願いします

※本メールはPA-APIをご利用中の皆様、または過去にご利用いただいたことがある皆様にお送りしております。

平素よりAmazonアソシエイト・プログラムをご利用いただき、誠にありがとうございます。

このたび、PA-API v5エンドポイントは、2026年5月15日(金)をもってサービスを終了いたします。PA-APIを利用したコンテンツへの影響を避けるため、同日までに新しいCreators APIへの移行をお願いいたします。移行手順の詳細については、 こちらの資料をご確認ください。

–2026/04/07

4月頭にやってきて1か月後に完全に廃止にしますなんて連絡が来ました。2年そこらしかまだ今のを使っていないのと、一つ前のメッセージだとまだOffersV2なら使えるよ、みたいな書き方をしていた割には突然のサービス終了宣言で驚いてしまいました。

では、さっそく移行作業を進めていきましょう。ちなみに、今の自分のシステムは上記のリンクのページのコードをベースにしていますが、こんな感じで価格・画像・商品URLなどの情報もとれます。PA-APIと同じことが可能です。

目次

AWSv4とOAuth2.0の違い

Creators APIが長く使えることを祈りながらシステムを移行させていきます笑

ひとまず、公式のリファレンスから読んでみます。すると、主な違いについては、

主な違いは、AWS Signature Version 4認証からOAuth 2.0への移行です。これにより、認証プロセスが簡素化され、トークンのキャッシュが可能になります。すべてのリクエストおよびレスポンスパラメータは、PascalCaseからlowerCamelCaseに変換されています。

適当に翻訳しましたが、こんな感じの違いらしいです。確かに今までAWSv4の認証をコードで書いて使っていましたので、この部分は明確に変換しなければいけないようです。というか今までガチガチのAWS固めっていうのが微妙な気がするので、標準的なOAuth 2.0への移行なのでこれは楽に実装できそうです。

あとはリクエストパラメータの変数名の命名規則が変わるようです。お恥ずかしい話ですが、私も普段プログラムを仕事で書きますが、命名規則のPascalCaseとlowerCamelCaseというのが最初に翻訳しつつよくわかっていませんでした。無知というのは恥ずかしいですね。こんな記事を見に来る人は知っているかと思いますが、それぞれの命名規則について簡単に説明を残しておきます(自分へのメモも兼ねて…)

PascalCaseは以下のように先頭を大文字、意味のあるところの区切りも大文字にする書き方です。この「PascalCase」という書き方もそれに倣っています。

PascalCase
ItemIds
PartnerTag

それに対してlowerCamelCaseは先頭は小文字、それ以外はPascalCaseに倣うという感じのようです。

lowerCamel
itemIds
partnerTag

こんな感じですね。私が薄学なもので、他にも代表的な記法はいくつかあるようです(参考:Qiita)。

  • lower_snake_case
  • UPPER_SNAKE_CASE
  • kebab-case
  • Hungarian Notation
  • dot.case

詳細は参考ページを見ていただければいいですが、うちの職場では組み込みの扱いが名なのでHungarian Notationが使われていますね。書かれている通りC,C++の世界なのでトラディッショナルな記法の世界で自分は生きていたようです。とはいえ、どの書き方も何処かで見た覚えがある書き方で、こんな規則名だったのかという感じのイメージですね。

少し話が脱線しましたが、認証方法と命名規則が主に変わったということでそれに合わせてコードを変えてみます。以前にPA-APIに対応したときの表示はそのまま使えるので、内部の値を差し替える感じで行こうと思います。

AWSv4とOAuth2.0の違い

OAuth2.0の仕組みとAWS v4の違いについて理解しましょう。

AWSv4の認証は自前で書くとそれなりに面倒です。それ以外のAPIがあればそれを使えば多少は楽なのですが、結局それの使い方を調べたりするとこれも時間的コストがかかりますね。

自前で実装する際の中身はHMAC-SHA256を適切なデータ・手順・鍵で計算できているかというのがあります。計算したハッシュをサーバに送り付けても、間違ってたら問答無用で跳ね返されて終わりとという、血も涙もないサーバ応答で何を間違っているかわからないう、デバッグの観点から見ても面倒な代物です。加えて、HMAC-SHA256ということは、64ラウンド圧縮を2回挟んでいることになるので、ハッシュとしては強固なのですが、裏を返せばそれだけサーバの計算リソースを使っていることになります。

一方でOAuthは特定のフォーマットに従って、サーバへリクエストを送って、何かしらの値が戻ってくるという通信上の形式が規格化されたものになります。

[特定フォーマット]->[サーバ]--(サーバ内の処理:ブラックボックス)-->[レスポンス]

こうなるので、ただ特定の値をサーバに投げ込めばレスポンスをもらえる、あくまで権限を安全に渡すための仕組みでしかありません。ここで戻ってくるレスポンスを一時トークンとして扱うというのがCreators APIの作りになっています。

そして、この投げ込む値というのは今回のCreators APIの仕様を見ると複雑な計算を必要としないため、サーバの負荷が軽減されることがわかります。そのトークンの計算をAmazonのサーバが受け持つことになります。ある意味サーバ依存のボトルネックがここにできてしまう可能性もありますが、ここは自分のサーバの計算負荷が下がることを素直に喜びます。

また、公式の比較表を見ると”Bearer token (valid for 1 hour, cacheable)”と表記があるので、AWSv4のときはアクセス毎に必要だった計算をする必要がなくなり、1時間まではキャッシュできるようになります。なので、通信としても減らすことができるということですね。

こう文字で書くと意味色々変わっているのですが、最終的にエンドポイントに投げる値が今まではANSI・要求値・AWSv4の署名だったものが、署名がOAuth2.0によって渡されるトークンに置き換わっただけにすぎません。

変数名がlowerCamelCaseに変わっているので、コード側でも些細な変更が必要ですが、それを除けばAWSv4の署名を別トークンに置き換えるだけと思えば楽ではないしょうか。というわけで実装してみます。

事前に認証情報を準備する

ここからコードを書いていきたい気持ちはありますが、その前に認証情報が変更になるため、新規で認証情報を発行す津必要があります。個人的には構造や使い道がわかりにくかったので、それを紹介しておきます。

初めにアソシエイトのホームに行き、
メインメニュー→ツール→クリエイターAPIと進みます。

アプリケーションのところで「アプリケーションの作成」をし、新しい認証情報を追加を選びます。すると認証情報が書かれたCSVがダウンロードできるためそれを保存しておきます。これはこの時以外は保存することができないので、必ず保管しておいてください。この認証情報を追加しないとまず使えないところから一瞬わかりませんでした。

ここで出力されたファイルの中身を見るとこれも若干わかりにくい部分があると思います。中身を見ると以下の項目が存在しますね。それぞれの意味合いが以下です。

項目意味
Application Id自分が作成したアプリのID
OAuth2.0の処理フローでは不要
Credential IdOAuth2.0の処理フローで使うID
SecretOAuth2.0の処理フローで秘密鍵
Version資格情報のバージョン
処理で分岐する可能性がある

関数の引数として必要なのが本来はCredential IdとSecretのはずなのですが、面倒なことにVersionによって投げ込むURLやそのヘッダー・ペイロードが異なるという仕様になっています(Creators APIの中ですらきちんと整合性が取れていないのか…)。

おそらく古いバージョンが出てくることはないと思うので、他のところで使いまわす予定がなければ、ハードコーディングで分けてしまってもよいと思います。3以降かどうか、なので今後発行する人は3以降になると思われるので、それに合わせるだけでもいいと思います。自分は一応両方書いてはみましたが、2系の認証情報がないので試すことができないので、もしやってみた方がいたら教えてください。

認証情報が発行されたらコード側で検証ができるので試していこうと思います。

WordPressで実装してみる

移行については公式からもガイドがありますが、そこまでパッとしない例なので、要点をまとめつついきます。

手順にも書かれていますが、AWSv4に関連するロジックは一切使用しないので、コメントアウトなり別ファイルに分けておきます。自分の場合はプラグインで実装しているので、それに準じた書き方のサンプルを提示します。

初めにOAuth2.0に対応した部分を書きます。公式リファレンスにわかりくい感じですが、どこに認証を投げればいいかの情報などが書かれています。リファレンス内の「Using cURL」の部分を参照してください(一応は会員用のリンクかと思うのでここでは伏せます)。日本の場合だと接続先は以下のサーバです。

    VersionURL
    2.3creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token
    3.3api.amazon.co.jp/auth/o2/token

    また、cURLで投げつけるパラメータの構成が違います。これも公式リファレンスに分けて記載されていますね。これを実装すると、version2.3のときのbodyとheaderについてはこのようになります。

    // v2.3 の場合 (Cognito)
    $token_url = "https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token";
    $token_args = [
        'headers' => [
                Authorization' => 'Basic ' . base64_encode($id . ':' . $secret),
                'Content-Type'  => 'application/x-www-form-urlencoded',
            ],
            'body' => 'grant_type=client_credentials&scope=creatorsapi/default',
    ];

    3.3の時はこのようになります。

    // v3.3 の場合 (LwA)
    $token_url = "https://api.amazon.co.jp/auth/o2/token";
    $token_args = [
        'headers' => ['Content-Type' => 'application/json'],
        'body'    => json_encode([
                        'grant_type'    => 'client_credentials',
                        'client_id'     => $id,
                        'client_secret' => $secret,
                        'scope'         => 'creatorsapi::default',
        ]),
    ];

    となります。このとき、$idは事前に用意した「Credential Id」を、$secretは「secret」の値が入る形になります。これを指定先にcURLで送ることになりますが、Wordpressには便利なwp_remote_post()関数があるため簡単に実装が可能です。以下のようにすることでアクセストークンを取得できます。

    $token_res = wp_remote_post($token_url, $token_args);
    $token_body = json_decode(wp_remote_retrieve_body($token_res));
    $access_token = $token_body->access_token ?? null;

    これでアクセストークンを入手できましたが、1時間のキャッシュが可能であることが公式で書かれているので、set_transient()で一定時間キャッシュに保存しておくとよいでしょう。少しぴったりだと切れてしまう可能性があるので、少し短めに設定して保存しておくとよいと思います。ここまでをコードまとめるとこんな感じです。バージョンによる処理分岐、トークンのキャッシュ化まで実装しています。

        // 1. トークンの取得
        $access_token = get_transient('amazon_creators_token');
    
        if (!$access_token) {
            // バージョンによってURLと形式を切り替え
            if (strpos($version, '2') === 0) {
                // v2.x の場合 (Cognito)
                $token_url = "https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token";
                $token_args = [
                    'headers' => [
                        'Authorization' => 'Basic ' . base64_encode($id . ':' . $secret),
                        'Content-Type'  => 'application/x-www-form-urlencoded',
                    ],
                    'body' => 'grant_type=client_credentials&scope=creatorsapi/default',
                ];
            } else {
                // v3.x の場合 (LwA)
                $token_url = "https://api.amazon.co.jp/auth/o2/token";
                $token_args = [
                    'headers' => ['Content-Type' => 'application/json'],
                    'body'    => json_encode([
                        'grant_type'    => 'client_credentials',
                        'client_id'     => $id,
                        'client_secret' => $secret,
                        'scope'         => 'creatorsapi::default',
                    ]),
                ];
            }
    
            $token_res = wp_remote_post($token_url, $token_args);
            $token_body = json_decode(wp_remote_retrieve_body($token_res));
            $access_token = $token_body->access_token ?? null;
    
            if ($access_token) {
                set_transient('amazon_creators_token', $access_token, 3500);
            }
        }
    
        if (!$access_token) return false;

    このトークンを使ってアクセスしていきますが、これは以前に作成したコードからほぼそのままでいけます。lowerCamelCaseに値を変更するぐらいで何とかなります。参照可能な値に関してはPA-APIから変わっていないようですが、API Reference>Operations>GetItemsに記載があります。

    ひとまず自分のは今まで通りの感じで実装してみます。面倒なのが、トークンを得るほかにこのデータを取得するタイミングで2.x系のみ追加でヘッダが必要な点です。今発行すれば3系なのでこのハンドリングはなくてもいいかもしれませんね。

        // 2. メインのAPIリクエスト
        $api_url = "https://creatorsapi.amazon/catalog/v1/getItems";
    
        // ヘッダーの作成
        $headers = [
            'Content-Type'  => 'application/json',
            'x-marketplace' => 'www.amazon.co.jp',
        ];
    
        // v2.x の場合のみ、Authorization ヘッダーに Version を含める必要がある
        if (strpos($version, '2') === 0) {
            $headers['Authorization'] = "Bearer $access_token, Version $version";
        } else {
            $headers['Authorization'] = "Bearer $access_token";
        }
    
        $payload = json_encode([
            "itemIds"    => [$asin],
            "itemIdType" => "ASIN", // 明示的に追加
            "marketplace" => "www.amazon.co.jp",
            "partnerTag" => "(ここに自分のパートナータグ)",
            "resources"  => [
                "images.primary.large",
                "itemInfo.title",
                "offersV2.listings.price",
    			"offersV2.listings.condition",
    			"offersV2.listings.availability"
            ]
        ]);
    
        $response = wp_remote_post($api_url, [
            'headers' => $headers,
            'body'    => $payload,
            'method'  => 'POST',
        ]);
    
        return wp_remote_retrieve_body($response);

    $asinは取得したいASINが入ります。これの戻りの値がペイロードの部分になるので呼び出し先でデコードすればデータを取り出せます。

    全体を関数にするとこんな感じです。

    function fetch_amazon_product_data($asin, $id, $secret, $version = '3.3') {
        // 1. トークンの取得
        $access_token = get_transient('amazon_creators_token');
    
        if (!$access_token) {
            // バージョンによってURLと形式を切り替え
            if (strpos($version, '2') === 0) {
                // v2.x の場合 (Cognito)
                $token_url = "https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token";
                $token_args = [
                    'headers' => [
                        'Authorization' => 'Basic ' . base64_encode($id . ':' . $secret),
                        'Content-Type'  => 'application/x-www-form-urlencoded',
                    ],
                    'body' => 'grant_type=client_credentials&scope=creatorsapi/default',
                ];
            } else {
                // v3.x の場合 (LwA)
                $token_url = "https://api.amazon.co.jp/auth/o2/token";
                $token_args = [
                    'headers' => ['Content-Type' => 'application/json'],
                    'body'    => json_encode([
                        'grant_type'    => 'client_credentials',
                        'client_id'     => $id,
                        'client_secret' => $secret,
                        'scope'         => 'creatorsapi::default',
                    ]),
                ];
            }
    
            $token_res = wp_remote_post($token_url, $token_args);
            $token_body = json_decode(wp_remote_retrieve_body($token_res));
            $access_token = $token_body->access_token ?? null;
    
            if ($access_token) {
                set_transient('amazon_creators_token', $access_token, 3500);
            }
        }
    
        if (!$access_token) return false;
    
        // 2. メインのAPIリクエスト
        $api_url = "https://creatorsapi.amazon/catalog/v1/getItems";
    
        // ヘッダーの作成
        $headers = [
            'Content-Type'  => 'application/json',
            'x-marketplace' => 'www.amazon.co.jp',
        ];
    
        // v2.x の場合のみ、Authorization ヘッダーに Version を含める必要がある
        if (strpos($version, '2') === 0) {
            $headers['Authorization'] = "Bearer $access_token, Version $version";
        } else {
            $headers['Authorization'] = "Bearer $access_token";
        }
    
        $payload = json_encode([
            "itemIds"    => [$asin],
            "itemIdType" => "ASIN", // 明示的に追加
            "marketplace" => "www.amazon.co.jp",
            "partnerTag" => "thunsuke-22",
            "resources"  => [
                "images.primary.large",
                "itemInfo.title",
                "offersV2.listings.price",
    			"offersV2.listings.condition",
    			"offersV2.listings.availability"
            ]
        ]);
    
        $response = wp_remote_post($api_url, [
            'headers' => $headers,
            'body'    => $payload,
            'method'  => 'POST',
        ]);
    
        return wp_remote_retrieve_body($response);
    }

    以前のコードは面倒で全てくっつけていましたが、以前のコードも切り分けると、関数の引数が3つになるような構造でした。今回のコードも観ての通り、asin,id,.secretの3つが引数でこれは前回と変わらないので、コードの変更に関しては割と最小限で済む感じで移行できます。

    ただ、この戻り値を使う(デコード)する際にパラメータ名がlowerCamelCaseになっているのでそれは対応する必要がありました。とはいっても本当に先頭を小文字に戻すだけで対応できました。

    まとめ

    PA-APIからCreators APIに乗り換えました。たった2年で変更かと思いましたが、コード的には比較的互換を持った状態で移植できる状態だったので、割と簡単に移植できたほうかと思います。

    パラメータ名もモダンにするためかlowerCamelCaseに変更になっていましたが、ここが元のままならもっと楽だったというか変更影響は小さく済んだのかなとも思います。ただ、パラメータ名を変更するだけではあるので、基本的なロジックに影響が無かったのはよかったです。

    今後もこういった変更はあるのかもしれませんが、Creators APIについては長持ちして欲しいと思います。10年ぐらいはこのままで運用させて欲しいですね…

    以上です。お読みいただきありがとうございました。

    投稿日:
    カテゴリー: TOOL雑記

    コメントする

    メールアドレスが公開されることはありません。 が付いている欄は必須項目です