Home / Blog / Amazon Spain Product API: amazon.es Data in EUR with Full History

Amazon Spain Product API: amazon.es Data in EUR with Full History

Get Amazon Spain product data with an API: marketplace ID A1RKKUPIHCS9HS queries amazon.es and returns prices in EUR. amazon.es has full price history and Buy Box holder data, and its bestseller lists take Spanish category names. This guide covers the marketplace values, Spanish page text, the category tree's gaps and a tested Python script that shows where Amazon itself keeps the Buy Box.

November 06, 2026
8 min read
SellerMagnet Team
Share & Bookmark
Terminal running a Python script that reads amazon.es bestsellers by Spanish category name and shows, per product, the Buy Box in euros and whether Amazon itself held it in the last 30 days

To get Amazon Spain product data, call the SellerMagnet API with marketplaceId=A1RKKUPIHCS9HS: requests go to amazon.es and prices come back in EUR. Every endpoint answers on this store, including price history, Buy Box holder history, estimated sales and the EAN to ASIN converter. Three details matter for Spanish integrations: history prices arrive as integer euro cents, page text comes back in Spanish, and bestseller lists take Spanish category names, with gaps you should know about.

Key Takeaways

  • amazon.es is marketplace A1RKKUPIHCS9HS, priced in EUR, default postcode 28001.
  • All ten endpoints answer on amazon.es: it is one of 11 marketplaces with price history, estimated sales and the ASIN converter.
  • Amazon sells first-party on amazon.es as seller A1AT7YVPFBWXBL; statistics uses that ID for amazonPrice and shareBuyBox.
  • Bestsellers take Spanish names such as Cafeteras; an ambiguous or unknown name is a free 400.
  • In the API's amazon.es tree, 23 of 45 departments (pets, DIY, sports, garden, books) have no subcategories: request those by slug.

Amazon Spain product API at a glance

A1RKKUPIHCS9HS is the same marketplace ID Amazon's Selling Partner API uses for Spain. Requests look the same as on any other store: GET, query parameters, the key in the X-Api-Key header. What changes are the values below. Offers and search use the default postcode 28001 unless you send geo_location (lookup always does), and on an EU store the price a buyer pays includes VAT. amazon.es prints prices with Spanish separators (1.299,99 €), but the API returns plain numbers such as 1299.99. Amazon's own APIs for amazon.es depend on your account type: the Selling Partner API's catalog calls are for sellers, and the Creators API is for Associates with at least 10 qualifying sales in the past 30 days. This API needs only an API key.

amazon.es at a glance.
Itemamazon.es
Marketplace IDA1RKKUPIHCS9HS
Storeamazon.es
CurrencyEUR, currencySymbol "€" (Euro)
Default postcode28001 (Madrid), used when geo_location is not sent
Amazon's own seller IDA1AT7YVPFBWXBL
History endpointsanswer: statistics, estimated sales, ASIN converter
listedSinceDate (lookup)filled from "Producto en Amazon.es desde"
Page languageSpanish: titles, bullets and category names
Bestseller category treeamazon.es's own: 45 top-level, 25,842 nodes

The amazon.es entry of /amazon-get-marketplaces (data is keyed by marketplace ID)

{
  "A1RKKUPIHCS9HS": {
    "currency_code": "EUR",
    "currency_name": "Euro",
    "currency_symbol": "€",
    "geo_location": "28001",
    "marketplace_domain": "amazon.es",
    "marketplace_name": "Amazon ES"
  }
}

Does amazon.es have price history in the API?

Yes. Lookup, offers, search, bestsellers, deals and seller feedback only check that the marketplace ID is valid and answer on all 23 stores. The three history endpoints cover 11 marketplaces, and amazon.es is one of them, next to amazon.de, amazon.fr, amazon.it and amazon.co.uk. Stores such as amazon.nl, amazon.com.be or amazon.pl get a free 400 "This endpoint is not available for the requested marketplace" for the same calls. On amazon.es each costs 1 credit and returns data. Prices come in three shapes: lookup reports the featured item price in decimal euros without shipping, offers adds shipping and does not round the Buy Box total, and statistics counts in euro cents, so a 24,99 € product with free delivery reads 24.99, 24.99 and 2499.

Terminal-theme table of the SellerMagnet API endpoints that answer for amazon.es and what each call costs
Every listed endpoint answers on amazon.es, the three history endpoints included.

Which amazon.es bestsellers does Amazon itself win?

Before you source a product for amazon.es, check whether Amazon sells it first-party and keeps the Buy Box. The script below reads the top bestsellers of Spanish categories by name, checks from data.link that each name landed in the department you meant, and then asks statistics for every new ASIN: the Buy Box price, Amazon's own offer and shareBuyBox. A list read in the wrong department is ignored before any statistics credit is spent, a product that ranks in two categories is checked once, and a 401 or 403 stops the run. It uses sellermagnet.py (ApiError, new_session) and retry.py (get_with_retry) from the Python quickstart.

spain_buybox_scan.py: Buy Box and Amazon's presence for the top bestsellers of Spanish categories

"""Amazon Spain (amazon.es): which bestsellers in a Spanish category does Amazon itself keep the Buy Box on?

marketplaceId A1RKKUPIHCS9HS = amazon.es, priced in EUR. Two endpoints, 1 credit per billed call:
  /amazon-bestsellers         category_id takes a category NAME as amazon.es shows it ("Cafeteras"). data.link shows
                              the department the name was read as (.../gp/bestsellers/<department>/<id>), so the
                              script checks it before spending more credits. An ambiguous or unknown name is a
                              free 400.
  /amazon-product-statistics  amazon.es is one of the 11 marketplaces with history, so this answers with data.
                              buyBoxPrice and amazonPrice are euro cents incl. shipping ("N/A" or null = none);
                              shareBuyBox False = Amazon (seller A1AT7YVPFBWXBL) held the Buy Box in the last 30 days.

Helpers: sellermagnet.py and retry.py from https://sellermagnet-api.com/blog/amazon-product-api-python
"""
import requests

from retry import get_with_retry
from sellermagnet import ApiError, new_session

MARKET = "A1RKKUPIHCS9HS"              # amazon.es
CATEGORIES = [                         # (name or slug as amazon.es shows it, department it must land in)
    ("Cafeteras", "kitchen"),
    ("Cafeteras individuales", "kitchen"),
    ("Comida para perros", "pets"),
    ("Auriculares", "electronics"),
    ("pets", "pets"),
]
TOP = 3                                # ranks per category; each new ASIN costs one statistics call
MAX_FAILED = 3                         # 502/503 are billed on every attempt: stop after 3 calls that keep failing


class Stop(Exception):
    """401/403 (key or credits gone) or a marketplace without history: every further call fails the same way."""


def eur(value):
    """24.99 -> '24,99 €' (Spanish separators for the report; the API sends plain numbers)."""
    if value is None:
        return "-"
    return f"{value:,.2f}".replace(",", "_").replace(".", ",").replace("_", ".") + " €"


def cents(value):
    """Statistics prices are euro cents; "N/A", null, 0 or a bool mean no price, never 0,00 €."""
    if isinstance(value, int) and not isinstance(value, bool) and value > 0:
        return value / 100
    return None


def fetch(session, endpoint, **params):
    """(data, None) on success, (None, note) on a per-row error. get_with_retry retries 429/502/503, 500 once."""
    try:
        return get_with_retry(session, endpoint, marketplaceId=MARKET, **params), None
    except ApiError as err:
        if err.status in (401, 403):
            raise Stop(str(err))
        if err.status == 400 and "not available for the requested marketplace" in str(err):
            raise Stop("no history endpoints on this marketplace (free 400)")
        if err.status == 404:
            return None, "billed 404"   # charged, and a retry would only buy another 404
        if err.status == 400:
            return None, str(err)       # the API's own message says what to fix
        return None, f"error {err.status}"
    except (requests.ConnectionError, requests.Timeout) as err:
        return None, f"error {type(err).__name__}"


def department(link):
    """'https://www.amazon.es/gp/bestsellers/kitchen/13713554031?pg=1' -> 'kitchen'; a top-level list -> its slug."""
    if "/gp/bestsellers/" not in link:
        return None
    return link.split("?")[0].split("/gp/bestsellers/")[1].split("/")[0]


def main():
    if not 1 <= TOP <= 50:   # count above 50 is a billed 400: a bestseller page holds 50 products
        print(f"TOP={TOP}: use 1 to 50, nothing was sent")
        return
    session = new_session()
    print(f"amazon.es ({MARKET}): top {TOP} bestsellers per category, then statistics per new ASIN\n")
    seen, failed, known, amazon_held = {}, 0, 0, 0
    try:
        for name, want in CATEGORIES:
            if failed >= MAX_FAILED:
                raise Stop(f"{failed} calls kept failing")
            data, note = fetch(session, "amazon-bestsellers", category_id=name, count=TOP)
            if data is None:
                failed += note.startswith("error")
                print(f"{name}: {note}\n")
                continue
            got = department(data.get("link") or "")
            if got != want:   # a name can match a node in another department: don't pay statistics for it
                print(f"{name}: read as {got or '?'}/{data.get('categoryId')}, not {want}; list ignored (1 credit)\n")
                continue
            print(f"{name} -> {data.get('categoryId')} ({got})")
            print(f"  {'#':>2} {'asin':<10} {'list':>10} {'Buy Box':>10} {'Amazon':>10} {'amz30d':<6} note")
            for card in data.get("bestsellers") or []:
                asin, rank = card.get("asin"), card.get("rank") or "-"
                price = (card.get("price") or {}).get("price")   # bestseller page price, not the Buy Box
                if not asin:
                    print(f"  {rank:>2} {'-':<10} {eur(price):>10}  card without ASIN, skipped")
                    continue
                if asin in seen:
                    print(f"  {rank:>2} {asin:<10} {eur(price):>10}  also #{seen[asin]}, not checked twice")
                    continue
                seen[asin] = f"{card.get('rank')} in {name}"
                if failed >= MAX_FAILED:
                    raise Stop(f"{failed} calls kept failing")
                stats, note = fetch(session, "amazon-product-statistics", asin=asin)
                if stats is None:
                    failed += note.startswith("error")
                    print(f"  {rank:>2} {asin:<10} {eur(price):>10}  statistics {note}")
                    continue
                share = stats.get("shareBuyBox")   # True = Amazon did NOT hold the Buy Box in the last 30 days
                flag = "?" if share is None else ("no" if share else "yes")
                known += share is not None
                amazon_held += share is False
                box, own = cents(stats.get("buyBoxPrice")), cents(stats.get("amazonPrice"))
                note = "nobody holds the Buy Box" if box is None else ""
                print(f"  {rank:>2} {asin:<10} {eur(price):>10} {eur(box):>10} {eur(own):>10} {flag:<6} {note}"
                      .rstrip())
            print()
    except Stop as err:
        print(f"stopped: {err}")
    print(f"Amazon held the Buy Box in the last 30 days on {amazon_held} of {known} products with a readable "
          "holder history")


if __name__ == "__main__":
    main()

Output (illustrative data: a retried 502, a billed 404, a product in two lists, a name read in the wrong department and an ambiguous name)

amazon.es (A1RKKUPIHCS9HS): top 3 bestsellers per category, then statistics per new ASIN

Cafeteras -> 13713554031 (kitchen)
   # asin             list    Buy Box     Amazon amz30d note
   1 B0ESCAF001   299,00 €   299,00 €   299,00 € yes
   2 B0ESCAF002    59,99 €    62,99 €    64,99 € no
   3 B0ESCAF003    24,95 €    24,95 €          - no

Cafeteras individuales -> 2165185031 (kitchen)
   # asin             list    Buy Box     Amazon amz30d note
   1 B0ESCAF002    59,99 €  also #2 in Cafeteras, not checked twice
   2 B0ESCAF004    64,90 €  statistics billed 404
   3 -             19,99 €  card without ASIN, skipped

Comida para perros: read as luxury/13442206031, not pets; list ignored (1 credit)

Auriculares: 400: 'Auriculares' matches 4 categories on amazon.es. Pass the category_id of the one you want.

pets -> pets (pets)
   # asin             list    Buy Box     Amazon amz30d note
   1 B0ESPET001    12,49 €          -          - no     nobody holds the Buy Box
   2 B0ESPET002    18,99 €    18,99 €    18,99 € yes
   3 B0ESPET003          -    21,99 €          - ?

Amazon held the Buy Box in the last 30 days on 2 of 5 products with a readable holder history
  • amz30d yes comes from shareBuyBox false: Amazon (A1AT7YVPFBWXBL) held the Buy Box at some point in the last 30 days. no means it did not, which is not a promise that you would win it. ? means the holder history could not be read.
  • B0ESCAF002 (illustrative) shows Amazon selling at 64,99 € while a cheaper seller holds the Buy Box at 62,99 €: an Amazon offer on the listing and Amazon holding the Buy Box are different things.
  • list is the price on the bestseller page (a range resolves to its low end), not the Buy Box. Buy Box and Amazon prices come from statistics in cents and include shipping.
  • Comida para perros cost 1 credit and was ignored: the name matched a node under Luxury Stores, not the pets department, so the script did not pay for statistics on that list.
  • B0ESPET001 has no Buy Box holder, so it shows dashes, never 0,00 €.
Terminal-theme sequence of the calls the script makes for one Spanish category on amazon.es, and the single billed call when a name lands in another department
One credit per list plus one per new ASIN; a list in the wrong department stops at one.

Credits for a category scan on amazon.es

1 credit per request, the same as on every store. The script spends 1 credit per bestseller list and 1 per new ASIN; a list in the wrong department costs its 1 credit and nothing more, and a repeated ASIN costs nothing. Retries add up: a 502 or 503 is charged on every attempt (get_with_retry makes up to 4), while a 500 without Retry-After is refunded. A billed 404 stays billed. The example run made 13 calls: 5 bestseller requests, of which the ambiguous name was a free 400, and 8 statistics calls for 7 products (one 502 retried once, one 404). That is 12 credits. Sending a count above 50 would be a billed 400, so the script refuses it before the first call. Plans and credit packs are on the pricing page; for the Buy Box check on a single listing, see is Amazon selling on this listing.

Can I use Spanish category names for amazon.es bestsellers?

Yes. category_id on /amazon-bestsellers takes a numeric browse node, a top-level slug such as kitchen or pets, or a category name as amazon.es shows it, in Spanish and in any letter case. A name match adds resolved_category (ID, name, path) to the response, beside data rather than inside it, so the quickstart's get() does not return it; data.categoryId and data.link still show the ID and department that were used. A name that fits several categories or none, and an unknown numeric ID, get a free 400 with a candidates list where there are matches; ApiError keeps only the message, so look the candidates up in the category explorer. English names such as "dog food" find nothing on amazon.es, and a numeric ID from another store (amazon.de's 3424591) is "Invalid CategoryId". For more on IDs, see Amazon category IDs for bestsellers.

The resolved_category field of /amazon-bestsellers with category_id=Cafeteras on amazon.es

{
  "resolved_category": {
    "category_id": "13713554031",
    "name": "Cafeteras",
    "path": "Hogar y cocina > Café y té > Cafeteras"
  }
}

The free 400 for category_id=Auriculares on amazon.es (no credit is taken)

{
  "candidates": [
    {
      "category_id": "52470778031",
      "name": "Auriculares",
      "path": "Coche y Moto - Piezas y accesorios > Electrónica para vehículos > Electrónica para coche > Auriculares"
    },
    {
      "category_id": "934312031",
      "name": "Auriculares",
      "path": "Electrónica > Radiocomunicación > Accesorios > Auriculares"
    },
    {
      "category_id": "4965385031",
      "name": "Auriculares",
      "path": "Luxury Stores > Instrumentos musicales > Equipo de DJ y VJ > Auriculares"
    },
    {
      "category_id": "22649664031",
      "name": "Auriculares",
      "path": "Videojuegos > Realidad virtual > Hardware independiente > Auriculares"
    }
  ],
  "error": "Bad request",
  "message": "'Auriculares' matches 4 categories on amazon.es. Pass the category_id of the one you want.",
  "success": false
}

The amazon.es tree has gaps

In the category tree the API checks against, 23 of amazon.es's 45 top-level departments have no subcategories, among them pets (Productos para mascotas), DIY, sports, garden, books and office products. For those, only the whole department list is available, by slug such as pets; a deeper amazon.es browse node from them is not in the tree and gets the free 400. Luxury Stores, on the other hand, holds 8,063 of the 25,842 nodes, including its own pets, sports, garden, DIY and books branches, which is why "Comida para perros" resolves to "Coberturas para comida" under Luxury Stores. Other names land in unexpected branches too: "Batidoras" resolves under Bebé. Check the department in data.link before you trust a list.

Spanish page text: what the API normalises and what stays Spanish

amazon.es answers in Spanish, so productInfo.title, bulletPoints, lookup's category names and the bestseller tree come back in Spanish. Some fields are normalised for you: offer conditions such as "Nuevo" or "Usado - Como nuevo" arrive as "New" and "Used - Like New", and delivery words like "mañana" become a deliveryDate. Lookup's listedSinceDate works on amazon.es: it reads the "Producto en Amazon.es desde" row (for example "4 noviembre 2024") and returns 2024-11-04. That date is when the listing was created, not necessarily when it first shipped.

Frequently Asked Questions

What is the Amazon Spain marketplace ID?

A1RKKUPIHCS9HS. Pass it as marketplaceId and the request goes to amazon.es with prices in EUR. A country code like "ES" or a domain like "amazon.es" is rejected with a free 400 Invalid marketplaceId.

Does the Amazon Spain API include price history?

Yes. amazon.es is one of the 11 marketplaces where /amazon-product-statistics, estimated sales and the ASIN converter answer with data, 1 credit each. History prices come back as integer euro cents, so divide by 100.

What seller ID does Amazon itself use on amazon.es?

A1AT7YVPFBWXBL. An offers Buy Box held by Amazon shows sellerId "Amazon" with this ID in amazonSellerId, and statistics uses it for amazonPrice and shareBuyBox on amazon.es.

Can I pass Spanish category names to the bestsellers endpoint?

Yes. "Cafeteras" resolves to 13713554031 and costs 1 credit. A name that fits several categories ("Auriculares" fits four) or none, including English names, gets a free 400. The response's data.link shows the department the name landed in.

Why can't I get a pet food bestseller list on amazon.es?

The category tree the API checks has no subcategories for 23 of amazon.es's 45 departments, pets included. Use the slug pets for the whole department; "Comida para perros" is read as a Luxury Stores node instead.

Bottom line: use A1RKKUPIHCS9HS for amazon.es, divide statistics prices by 100, send Spanish category names and check the department each one lands in. Because amazon.es has history coverage, a bestseller list becomes Buy Box, Amazon presence and price per product at one credit each. For the other stores, see the marketplace IDs list and endpoint coverage by marketplace; a free account includes 150 credits.

Related Articles

Continue exploring topics related to this article.

Back to Blog

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