Home / Blog / Amazon API Key Rotation Without Downtime: Zero-Credit Checks, Max 3 Keys

Amazon API Key Rotation Without Downtime: Zero-Credit Checks, Max 3 Keys

Rotate a SellerMagnet API key with zero downtime: generate a second key, confirm it is live with a free check, run both side by side, then delete the old one. Why Reset is not the same as a rotation, why a toggled-off key still counts toward the 3-key limit, and a tested Python script that checks a new key for free and falls back to the old one.

October 30, 2026
6 min read
SellerMagnet Team
Share & Bookmark
Terminal running a Python script that checks a new API key for free, then rotates real traffic onto it with the old key kept as a fallback

To rotate an Amazon API key without downtime, generate a second key while the old one keeps working (max 3 active keys per account; up to 3 can run in parallel), confirm the new key is live with a zero-credit check, move real traffic onto it with the old key kept as a fallback, then delete the old key. Resetting a key is a different action: it swaps the value of the same key slot immediately, so it breaks whatever still uses the old value and is not a zero-downtime rotation on its own.

Key Takeaways

  • A request with no parameters at all checks a key for free: a dead key answers 401 before any parameter is read, a live key answers the parameter gate's 400 - both cost 0 credits.
  • Credits live on the account, not on any one key, so a new key and an old key can run side by side for free during a rotation.
  • Reset replaces the value of the same key slot at once; the old value stops working immediately, so Reset is for killing a leaked key, not for a planned rotation.
  • The max-3 limit counts every key that is not deleted, whether it is active or toggled off - only Delete frees a slot for a new key.
  • A client that falls back to the old key on a 401 from the new one keeps every request working through the whole overlap window.

How do I check a new API key for free?

Every endpoint checks the API key before it reads any parameter, and the parameter gate runs before a credit is ever deducted. So a request with no parameters at all costs 0 credits either way: a dead or inactive key answers 401 "Invalid or inactive API key.", a key on an account with 0 credits ALSO answers 401 but with a different message, "Insufficient user credits.", and a live key with credits answers the parameter gate's 400 "Missing required parameter(s): asin, marketplaceId". Read the message, not just the status code, or a freshly generated key on an empty account looks identical to a dead one. Checking this as many times as you like during a rotation never spends a credit.

The free check's response body on a live key

{
  "success": false,
  "error": "Bad request",
  "message": "Missing required parameter(s): asin, marketplaceId"
}

Reset, Toggle off or Delete: which one for a rotation?

Reset keeps the same key slot but swaps its value right away, so it is the opposite of zero-downtime: use it to kill a leaked key immediately. Toggle off pauses a key but does not delete it, and it still counts toward the 3-key limit, so it does not free up room for a new key either. Only Delete (a soft delete; the row and its usage logs stay for billing evidence) removes a key from the count, which is what makes room for the next rotation.

What each key action actually does.
ActionWhat changesCounts toward 3Old value
Generatenew key_id + valueYES, counts toward 3unaffected (shared credit pool)
Resetsame key_id, new valueno changeold value dead at once
Toggle offis_active = falseYES, still countsunaffected (just paused)
Deletesoft delete, deleted_at setNO, frees the slotunaffected
Terminal-theme table comparing Generate, Reset, Toggle off and Delete for an Amazon API key
Only Delete frees a slot; Toggle off still counts toward the limit of 3.

What does a zero-downtime rotation look like in code?

The script below generates (manually, in the dashboard) a second key, then checks it for free before sending any real traffic to it. Every real lookup tries the new key first; if the new key answers 401, the call falls back to the old key instead of failing, so nothing a user sees breaks during the overlap. It uses sellermagnet.py (API, ApiError) and retry.py (get_with_retry) from the Python quickstart, but builds its own session per key instead of calling new_session(), because it needs two keys open at once.

rotate_key.py - check the new key for free, then switch with a fallback

"""Zero-downtime Amazon API key rotation: confirm the new key for free, then move real traffic
onto it while the old key still answers as a fallback, and know when it is safe to delete the
old key.

Credits live on the ACCOUNT, not the key (sellermagnet.com API key transport facts): running the
old and the new key side by side during a rotation costs nothing extra, both draw the same
balance. The check below sends no parameters at all, which is free either way: the key is checked
BEFORE any parameter, so a dead key answers 401 "Invalid or inactive API key." and a live key
answers the parameter gate's 400 "Missing required parameter(s): asin, marketplaceId" - neither
response deducts a credit.
Helpers: sellermagnet.py (API, ApiError, get) and retry.py (get_with_retry) from
https://sellermagnet-api.com/blog/amazon-product-api-python; this script builds its own sessions
instead of calling sellermagnet.new_session(), because it needs two keys open at the same time.
"""
import os
import re

import requests

from retry import get_with_retry
from sellermagnet import API, ApiError

MARKETPLACE = "ATVPDKIKX0DER"                                     # amazon.com
ASINS = ["B0CL61F39H", "B0NOOFFR01", "B0FLAKY001", "not-an-asin"]
MAX_FAILED = 3                                                     # 502/503 are billed every attempt


def session_for(key: str) -> requests.Session:
    session = requests.Session()
    session.headers["X-Api-Key"] = key
    return session


def key_is_live(key: str) -> str:
    """Zero-credit check: no parameters at all, so every answer is free. The key is checked before
    any parameter is read, so a dead key answers 401 "Invalid or inactive API key." and a zero-credit
    account also answers 401, but with "Insufficient user credits." instead - distinct messages, same
    status. A valid key with credits answers the parameter gate's 400 "Missing required parameter(s)".
    Returns "live", "dead" or "no-credits"."""
    resp = session_for(key).get(f"{API}/amazon-product-lookup", timeout=120)
    try:
        message = resp.json().get("message", "")
    except ValueError:
        message = ""
    if resp.status_code == 401 and "Insufficient user credits" in message:
        return "no-credits"
    if resp.status_code == 401:
        return "dead"
    if resp.status_code == 400 and "Missing required parameter" in message:
        return "live"
    raise RuntimeError(f"unexpected key-check response {resp.status_code}: {resp.text[:200]}")


def rotate(old_key: str, new_key: str) -> None:
    status = key_is_live(new_key)
    if status == "dead":
        print("ABORT: new key is not live yet (401) - keep sending traffic on the old key.")
        return
    if status == "no-credits":
        print("ABORT: new key is valid but the account has 0 credits - add credits before switching.")
        return
    print("new key confirmed live (free check, 0 credits spent)\n")
    primary, fallback = session_for(new_key), session_for(old_key)
    used_fallback = failed = 0
    for raw in ASINS:
        asin = raw.strip().upper()
        if not re.fullmatch(r"[A-Z0-9]{10}", asin):
            print(f"{raw:<11} skipped: not a 10-character ASIN")
            continue
        if failed >= MAX_FAILED:
            print(f"stopped after {MAX_FAILED} failed calls")
            return
        try:
            data = get_with_retry(primary, "amazon-product-lookup", asin=asin, marketplaceId=MARKETPLACE)
            holder = "new"
        except ApiError as new_err:
            if new_err.status != 401:
                label = "not found (billed 404)" if new_err.status == 404 else f"error {new_err}"
                print(f"{asin:<11} new  {label}")
                failed += new_err.status >= 500
                continue
            used_fallback += 1
            try:
                data = get_with_retry(fallback, "amazon-product-lookup", asin=asin, marketplaceId=MARKETPLACE)
                holder = "old (fallback)"
            except ApiError as old_err:
                print(f"{asin:<11} both keys failed: {old_err}")
                failed += old_err.status >= 500
                continue
        price = data["buyBoxInfo"].get("price")
        shown = f"{price:.2f}" if isinstance(price, (int, float)) else "N/A"
        print(f"{asin:<11} {holder:<14} {shown}")
    print(f"\nfallback calls used: {used_fallback}")
    print("safe to delete the old key now" if used_fallback == 0 else
          "keep the old key active - traffic is still using it")


if __name__ == "__main__":
    rotate(os.environ["SELLERMAGNET_OLD_KEY"], os.environ["SELLERMAGNET_NEW_KEY"])

Output (illustrative data: a clean rotation, one refunded 500, no fallback needed)

new key confirmed live (free check, 0 credits spent)

B0CL61F39H  new            444.99
B0NOOFFR01  new            N/A
B0FLAKY001  new            19.99
not-an-asin skipped: not a 10-character ASIN

fallback calls used: 0
safe to delete the old key now
  • new key confirmed live means the zero-credit check passed; nothing has been charged yet and no real traffic has moved.
  • fallback calls used: 0 means every real lookup succeeded on the new key - safe to delete the old key right after.
  • A 401 from the new key mid-rotation is not an error to panic over: the script falls back to the old key for that one call and keeps counting, so you see exactly how many requests still needed the old key before you delete it.
  • Never delete the old key while fallback calls are still happening - the counter at the end of the run is the signal, not a fixed wait time.
Terminal-theme sequence of a zero-downtime API key rotation: check, switch, fallback window, delete
The new key is proven live before anything real is sent to it.

What does a key rotation cost?

Nothing beyond the normal 1 credit per real request: the zero-parameter check is free on both the new and the old key, and running two keys at once costs nothing extra because credits are tracked per account, not per key. The only thing a rotation spends is the same credits your traffic would have spent anyway, whichever key answers it. For the difference between sending a key as a header or a query parameter, see API key: header vs. query string.

Frequently Asked Questions

Does rotating an API key cost credits?

No. Generating, resetting, toggling and deleting a key are account actions with no credit cost, and credits live on the account, not on any one key, so running an old and a new key side by side during a rotation spends nothing extra.

Is Reset a zero-downtime rotation?

No. Reset keeps the same key slot but swaps its value immediately, so whatever still uses the old value breaks at once. Use Reset only when a key leaked and needs to die right now; for a planned rotation, generate a second key instead.

Why does deleting an old key matter if I already turned it off?

The 3-key limit counts every key that is not deleted, active or not. A toggled-off key still fills one of your 3 slots, so the next rotation has nowhere to put a new key until the old one is actually deleted.

How do I check a new key works before switching real traffic to it?

Send a request to any endpoint with no parameters at all. A dead key answers 401 before the parameters are even read; a live key answers the parameter gate's free 400. Both responses cost 0 credits, so you can check as often as you like.

What happens if I switch traffic to the new key too early?

Nothing dangerous: a request on a key that is not yet valid gets a free 401, so a client that falls back to the old key on 401 keeps working through the whole overlap window with no failed request reaching your users.

Why does my new key's check also come back 401?

A dead key and a zero-credit account both answer 401, with different message text: "Invalid or inactive API key." versus "Insufficient user credits." A freshly generated key on an account with no credits left looks dead unless you read the message, not just the status code.

Bottom line: generate a second key, prove it is live with a free check, move traffic with an old-key fallback, and delete (not just toggle off) the old key once the fallback count hits zero. The API keys page in the dashboard is where Generate, Reset, Toggle and Delete all live, and a free account includes 150 credits to try it.

Ready to Extract Amazon Data at Scale?

Start building with SellerMagnet API today. Real-time product data, competitive pricing, and review analytics at your fingertips.

150 free API credits • No credit card required • Cancel anytime