試してみたブログ

AI関連・iPhone/Pixelなどのガジェット・音声入力・サーマルプリンタなど興味をある事をどんどん試してみた際の記録

Amazon CreatorsAPIが使える様になったので試す

試してみた

  • Amazon Product Advertising API(PA-API)がCreators APIとして置き換わった
  • amazonアソシエイトに登録し、3件の注文を獲得して承認を受ける
  • 30日で10件以上の発送済みがある場合のみAPIが200を返す

仕様まとめ

Amazon Creators API 最低限の疎通確認とハマりどころ

前提:使えるようになるまで

必要なもの

  1. Amazon アソシエイト承認済みアカウント(日本:affiliate.amazon.co.jp)
  2. 過去30日で 10 件以上の適格販売(発送済み) ← Creators API の利用資格条件
  3. https://affiliate.amazon.co.jp/creatorsapi で発行する Credential ID / Secret
  4. Partner Tag

注意点

  • アソシエイトアカウントが承認済みでも、Creators API の利用には 別途 過去30日10件のハードルがある
  • Amazonデバイス / Amazon Music / Prime Video / ギフトカードは「適格販売」にカウントされない
  • 売上が落ちて30日 0件状態になると 一時停止。発送が再開されると 約2日で自動復元

最低限の動作確認コード

.env を用意:

CREATORS_CLIENT_ID=amzn1.application-oa2-client.xxxxxxxx
CREATORS_CLIENT_SECRET=amzn1.oa2-cs.v1.xxxxxxxx
CREATORS_PARTNER_TAG=xxxxxx-22
CREATORS_MARKETPLACE=www.amazon.co.jp

疎通テストスクリプト:

import json, os, requests
from dotenv import load_dotenv
load_dotenv()

TOKEN_URL = "https://api.amazon.co.jp/auth/o2/token"
GET_ITEMS_URL = "https://creatorsapi.amazon/catalog/v1/getItems"

# 1. LWA でアクセストークン取得(client_credentials)
r = requests.post(TOKEN_URL,
    headers={"Content-Type": "application/json"},
    json={
        "grant_type": "client_credentials",
        "client_id": os.environ["CREATORS_CLIENT_ID"],
        "client_secret": os.environ["CREATORS_CLIENT_SECRET"],
        "scope": "creatorsapi::default",
    }, timeout=30)
r.raise_for_status()
token = r.json()["access_token"]
print(f"token ok: {token[:24]}...")

# 2. getItems で1件取得
r = requests.post(GET_ITEMS_URL,
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "x-marketplace": "www.amazon.co.jp",
    },
    json={
        "partnerTag": os.environ["CREATORS_PARTNER_TAG"],
        "itemIds": ["B0GGY53D74"],   # 任意のASIN
        "resources": [
            "images.primary.large",
            "itemInfo.title",
            "itemInfo.byLineInfo",
            "offersV2.listings.price",
        ],
    }, timeout=30)
print(r.status_code)
print(json.dumps(r.json(), ensure_ascii=False, indent=2))

成功時のレスポンス(getItems)

{
  "itemsResult": {
    "items": [{
      "asin": "B0GGY53D74",
      "detailPageURL": "https://www.amazon.co.jp/dp/B0GGY53D74?tag=...",
      "images": {"primary": {"large": {"url": "...", "width": 396, "height": 500}}},
      "itemInfo": {
        "title": {"displayValue": "Animage (アニメージュ) 2026年 05月号 [雑誌]"},
        "byLineInfo": {
          "brand": {"displayValue": "徳間書店"},
          "contributors": [{"name": "Animage編集部", "roleType": "author"}]
        }
      },
      "offersV2": {"listings": [{"price": {"money": {"amount": 856, "currency": "JPY"}}}]}
    }]
  }
}

これが返ってくれば疎通 OK。


使えないときの典型エラー

1. AssociateNotEligible(HTTP 403)

{
  "message": "Your account does not currently meet the eligibility requirements.",
  "reason": "AssociateNotEligible",
  "type": "AccessDeniedException"
}

原因: 過去30日で適格販売が10件未満。 対処: - アソシエイトのレポートで「過去30日・確定済み・発送済み」件数を確認 - 適格でない商品(Amazonデバイス、Prime Video、ギフトカード等)が混じってないか確認 - partner_tag が複数ある場合、別タグに売上が立っていないか確認 - 復元には 発送完了から約2日のラグ あり

補足:トークン取得(/auth/o2/token)は資格に関係なく通る。AssociateNotEligible が出るのは getItems / searchItems 側

2. ValidationException — resources のフィールド名間違い(HTTP 400)

{
  "message": "...failed to satisfy constraint: Member must satisfy enum value set: [searchRefinements, itemInfo.externalIds, ...]",
  "reason": "FieldValidationFailed",
  "type": "ValidationException"
}

よくある誤り: - offersV2.listings.programEligibility存在しない(KU 判定のために試したくなるが NG) - 任意の typo

searchItems で使える resources(実機検証で判明):

searchRefinements
parentASIN
itemInfo.title
itemInfo.byLineInfo
itemInfo.externalIds
itemInfo.classifications
itemInfo.manufactureInfo
itemInfo.productInfo
itemInfo.contentInfo
itemInfo.contentRating
itemInfo.features
itemInfo.technicalInfo
itemInfo.tradeInInfo
images.primary.small / medium / large / highRes
images.variants.small / medium / large / highRes
browseNodeInfo.browseNodes
browseNodeInfo.browseNodes.ancestor
browseNodeInfo.browseNodes.salesRank
browseNodeInfo.websiteSalesRank
offersV2.listings.price
offersV2.listings.condition
offersV2.listings.availability
offersV2.listings.dealDetails
offersV2.listings.isBuyBoxWinner
offersV2.listings.loyaltyPoints
offersV2.listings.merchantInfo
offersV2.listings.type
customerReviews.starRating
customerReviews.count

3. ValidationException — SearchIndex の値が無効(HTTP 400)

{
  "fieldList": [{
    "name": "InvalidParameterValue",
    "message": "The value Magazines provided in the request for SearchIndex is invalid."
  }],
  "type": "ValidationException"
}

原因: 日本のロケール(amazon.co.jp)では SearchIndex=Magazines は存在しない。 対処: 雑誌の検索でも SearchIndex=KindleStore(Kindle 版なら)or Books を使う。BrowseNodeId でカテゴリ絞り込みする。

4. ThrottleException(HTTP 429)

{
  "message": "Request rate limit exceeded.",
  "type": "ThrottleException"
}

原因: レート制限。Creators API は概ね 1 TPS 程度。 対処: - 呼び出し間に 1.0〜1.5 秒のウェイトを入れる - 429 を受けたら 3 秒スリープしてリトライ - 大量バッチは getItems(10 ASIN/req)を使ってリクエスト数を圧縮

実装例:

import time, threading

class CreatorsClient:
    def __init__(self, min_interval_sec=1.2):
        self._lock = threading.Lock()
        self._last_call_at = 0.0
        self._min_interval = min_interval_sec

    def _throttle(self):
        with self._lock:
            elapsed = time.time() - self._last_call_at
            if elapsed < self._min_interval:
                time.sleep(self._min_interval - elapsed)
            self._last_call_at = time.time()

5. トークン取得自体が失敗する

ステータス 原因
invalid_client CLIENT_ID / SECRET の typo、改行混入
invalid_scope scopecreatorsapi::default 以外にしている
unsupported_grant_type grant_typeclient_credentials 以外

Content-Typeapplication/json で JSON ボディを送ること(application/x-www-form-urlencoded のサンプルもあるが、api.amazon.co.jp の v3.3 は JSON で動作確認済)。


チートシート

項目
トークン URL https://api.amazon.co.jp/auth/o2/token
getItems URL https://creatorsapi.amazon/catalog/v1/getItems
searchItems URL https://creatorsapi.amazon/catalog/v1/searchItems
scope creatorsapi::default
token TTL 3600 秒(1 時間)
marketplace ヘッダ x-marketplace: www.amazon.co.jp
getItems 上限 1 リクエスト 10 ASIN
searchItems 上限 1 ページ 10 件、itemPage 1〜10 で最大 100 件
レート制限 約 1 TPS
利用資格 過去30日に 10 件以上の適格販売(発送済み)

Kindle Unlimited 判定の Tips

  • レスポンスに「KU 対象フラグ」は 存在しない
  • 代わりに browseNodeInfo.browseNodes の祖先を再帰的に辿り、id=3197885051(Kindle Unlimited:読み放題 ジャンル)が含まれるかでチェック
def is_kindle_unlimited(item):
    KU_NODE_ID = "3197885051"
    def has_ancestor(node, target):
        if node.get("id") == target:
            return True
        a = node.get("ancestor")
        return has_ancestor(a, target) if a else False
    for n in item.get("browseNodeInfo", {}).get("browseNodes", []):
        if has_ancestor(n, KU_NODE_ID):
            return True
    return False

resources に browseNodeInfo.browseNodes.ancestor を必ず含めること。