Home / Blog / Amazon Germany Product API: amazon.de Data in EUR with Full History

Amazon Germany Product API: amazon.de Data in EUR with Full History

Get Amazon Germany product data with an API: marketplace ID A1PA6795UKMFR9 queries amazon.de and returns prices in EUR. Unlike amazon.nl or amazon.pl, amazon.de has full price history, sales estimates and EAN lookups. This guide covers the price formats, German page text, category names and a tested Python script that checks a supplier list by EAN.

November 05, 2026
7 min read
SellerMagnet Team
Share & Bookmark
Terminal running a Python script that checks a German supplier list by EAN on amazon.de: Buy Box in euros, Amazon's presence and a monthly sales estimate per row

To get Amazon Germany product data, call the SellerMagnet API with marketplaceId=A1PA6795UKMFR9: requests go to amazon.de and prices come back in EUR. Every endpoint answers on this store, including price history, estimated sales and the EAN to ASIN converter, which several other European stores lack. Two details matter for German integrations: history prices arrive as integer euro cents, and titles, bullets and category names come back in German.

Key Takeaways

  • amazon.de is marketplace A1PA6795UKMFR9, priced in EUR, default postcode 10115.
  • All ten endpoints answer on amazon.de: it is one of 11 marketplaces with price history, estimated sales and the ASIN converter.
  • With free delivery, the same Buy Box reads 24.99 on lookup and offers but 2499 (euro cents) on statistics.
  • Amazon sells first-party on amazon.de as seller A3JWKAKR8XB7XF, which statistics uses for amazonPrice and shareBuyBox.
  • Bestsellers take German category names such as Kaffeemühlen; an ambiguous or unknown name is a free 400.

Amazon Germany product API at a glance

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 10115 unless you send geo_location (lookup always does), and on an EU store the price a buyer pays includes VAT. amazon.de prints prices with German separators (1.299,99 €), but the API returns plain numbers such as 1299.99. Amazon's own APIs for amazon.de 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.de at a glance.
Itemamazon.de
Marketplace IDA1PA6795UKMFR9
Storeamazon.de
CurrencyEUR, currencySymbol "€" (Euro)
Default postcode10115 (Berlin), used when geo_location is not sent
Amazon's own seller IDA3JWKAKR8XB7XF
History endpointsanswer: statistics, estimated sales, ASIN converter
listedSinceDate (lookup)filled from "Im Angebot von Amazon.de seit"
Page languageGerman: titles, bullets and category names
Bestseller category treeamazon.de's own: 51 top-level, 32,456 nodes

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

{
  "A1PA6795UKMFR9": {
    "currency_code": "EUR",
    "currency_name": "Euro",
    "currency_symbol": "€",
    "geo_location": "10115",
    "marketplace_domain": "amazon.de",
    "marketplace_name": "Amazon DE"
  }
}

Does amazon.de 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.de is one of them, next to amazon.co.uk, amazon.fr, amazon.it and amazon.es. That is the main difference to stores such as amazon.nl, amazon.com.be, amazon.pl or amazon.se, where statistics, estimated sales and the converter return a free 400 "This endpoint is not available for the requested marketplace". On amazon.de each of them costs 1 credit and returns data: the Buy Box price and its history, the holder history with Amazon's own seller ID, a monthly sales estimate, and the ASIN behind a barcode.

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

How do amazon.de prices come back?

In three shapes, depending on the endpoint. Lookup reports the featured item price without shipping, offers adds shipping and does not round the Buy Box total, and statistics counts in euro cents. A product that sells for 24,99 € with free delivery therefore reads 24.99, 24.99 and 2499. Mixing them without converting turns a stable price into a 100x jump; on an offer with paid delivery, lookup's item price also differs from the other two by the shipping cost.

Where the Buy Box price of one amazon.de product appears.
EndpointFieldUnitExample
/amazon-product-lookupproductInfo.buyBoxInfo.pricedecimal euros, item only24.99 or "N/A"
/amazon-product-offersbuyBox.totalPricedecimal euros, incl. shipping24.99 (round it)
/amazon-product-statisticsbuyBoxPriceinteger euro cents, incl. shipping2499 or "N/A"
/amazon-product-statisticsstats.buyBoxPriceHistory[date, cents] pairs["2026-10-01", 2499]
/amazon-searchlistingPrice.price.totalstring, two decimals"24.99"

Check a German supplier list by EAN in Python

German wholesale lists identify products by EAN, not ASIN, and that is where the history endpoints on amazon.de pay off. The script below reads a supplier CSV as a German Excel saves it (semicolons, decimal commas, a UTF-8 BOM), converts each EAN to an ASIN, reads the Buy Box and Amazon's presence from statistics, and adds a monthly sales estimate. It checks the EAN check digit, the price cell and duplicates before paying, skips the estimate when nobody holds the Buy Box, and stops on a 401 or 403. It uses sellermagnet.py (ApiError, new_session) and retry.py (get_with_retry) from the Python quickstart.

germany_ean_check.py: Buy Box, Amazon's presence and a sales estimate per EAN on amazon.de

"""Amazon Germany (amazon.de): check a German supplier list by EAN with the three history endpoints.

marketplaceId A1PA6795UKMFR9 = amazon.de, priced in EUR. amazon.de is one of the 11 marketplaces with price history,
so the converter, statistics and estimated sales answer it with data (amazon.nl, .pl, .se or .com.be get a free 400
for the same calls). Per EAN, at most 3 credits:
  /amazon-asin-converter                  ean-to-asin: the ASIN amazon.de lists for the barcode (first match only)
  /amazon-product-statistics              buyBoxPrice in euro cents incl. shipping ("N/A" = nobody holds it) and
                                          shareBuyBox (False = Amazon itself held the Buy Box in the last 30 days)
  /amazon-product-search-estimated-sells  estimated_monthly_sales: a model estimate, not a measurement
The list is a CSV saved by a German Excel: semicolons, decimal commas ("12,50") and EANs that Excel may have turned
into 4.00638E+12. Every value is checked before a credit is spent.

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

import requests

from retry import get_with_retry
from sellermagnet import ApiError, new_session

MARKET = "A1PA6795UKMFR9"              # amazon.de
SUPPLIER_CSV = "lieferant.csv"         # save as "CSV UTF-8 (durch Trennzeichen getrennt)"
COLUMNS = ["EAN", "Artikel", "EK netto"]
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 ean_ok(code):
    """GS1 check digit of an EAN-8, UPC-12, EAN-13 or GTIN-14: a typo fails here, not as a billed 400 or 404."""
    if not re.fullmatch(r"\d{8}|\d{12,14}", code):
        return False
    body, check = [int(d) for d in code[:-1]], int(code[-1])
    total = sum(d * (3 if i % 2 == 0 else 1) for i, d in enumerate(reversed(body)))
    return (10 - total % 10) % 10 == check


def euro(text):
    """German price cell -> float: "12,50" and "1.249,00" work; "1.249" is ambiguous (1249 or 1.249) -> None."""
    s = text.replace("€", "").replace(" ", "").strip()
    if re.fullmatch(r"\d{1,3}(\.\d{3})*,\d{1,2}|\d+,\d{1,2}", s):
        return float(s.replace(".", "").replace(",", "."))
    if re.fullmatch(r"\d+(\.\d{1,2})?", s):
        return float(s)
    return None


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


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
        return None, f"error {err.status}"
    except (requests.ConnectionError, requests.Timeout) as err:
        return None, f"error {type(err).__name__}"


def read_rows(path):
    with open(path, newline="", encoding="utf-8-sig") as fh:   # utf-8-sig: Excel writes a BOM
        reader = csv.DictReader(fh, delimiter=";")
        if reader.fieldnames != COLUMNS:
            raise Stop(f"header {reader.fieldnames} is not {COLUMNS}: fix the file, nothing was sent")
        return list(reader)


def check(session, asin):
    """(Buy Box price in euros or None, Amazon held it in the last 30 days, estimate or None, note, failed calls)."""
    stats, note = fetch(session, "amazon-product-statistics", asin=asin)
    if stats is None:
        return None, "?", None, f"statistics {note}", note.startswith("error")
    cents = stats.get("buyBoxPrice")
    box = cents / 100 if isinstance(cents, int) and not isinstance(cents, bool) and cents > 0 else None   # cents
    share = stats.get("shareBuyBox")   # True = Amazon did NOT hold the Buy Box in the last 30 days
    amazon = "?" if share is None else ("no" if share else "yes")
    if box is None:
        return None, amazon, None, "nobody holds the Buy Box, estimate skipped", False
    est, e_note = fetch(session, "amazon-product-search-estimated-sells", asin=asin)
    if est is None:
        return box, amazon, None, f"estimate {e_note}", e_note.startswith("error")
    return box, amazon, est.get("estimated_monthly_sales"), "", False


def main():
    session = new_session()
    try:
        rows = read_rows(SUPPLIER_CSV)
    except Stop as err:
        print(f"stopped: {err}")
        return
    print(f"amazon.de ({MARKET}): converter + statistics + estimated sales, at most 3 credits per EAN\n")
    print(f"{'ean':<13} {'asin':<10} {'EK netto':>10} {'Buy Box':>10} {'x EK':>5} {'amz30d':<6} {'est/mo':>6}  note")
    seen_ean, seen_asin, failed = set(), {}, 0
    for row in rows:
        raw = (row["EAN"] or "").strip()
        cost = euro(row["EK netto"] or "")
        if "E+" in raw.upper():
            print(f"{raw:<13} skipped: Excel turned the EAN into a number, the last digits are lost")
            continue
        if not ean_ok(raw):
            print(f"{raw:<13} skipped: not a valid EAN (check digit), the converter would bill it")
            continue
        if cost is None or cost <= 0:
            print(f"{raw:<13} skipped: purchase price {row['EK netto']!r} is ambiguous or not a euro amount")
            continue
        if raw in seen_ean:
            print(f"{raw:<13} skipped: duplicate row (a second check bills up to 3 more credits)")
            continue
        seen_ean.add(raw)
        if failed >= MAX_FAILED:
            print(f"stopped after {failed} failed calls")
            return
        try:
            conv, note = fetch(session, "amazon-asin-converter", asin=raw, conversion_direction="ean-to-asin")
            if conv is None:
                failed += note.startswith("error")
                why = "no match on amazon.de (billed 404)" if note == "billed 404" else f"converter {note}"
                print(f"{raw:<13} {'-':<10} {eur(cost):>10}  {why}")
                continue
            asin = conv.get("asin")
            if not asin:
                print(f"{raw:<13} {'-':<10} {eur(cost):>10}  converter returned no ASIN")
                continue
            if asin in seen_asin:
                print(f"{raw:<13} {asin:<10} {eur(cost):>10}  same ASIN as {seen_asin[asin]}, not checked twice")
                continue
            seen_asin[asin] = raw
            box, amazon, est, note, bad = check(session, asin)
        except Stop as err:
            print(f"stopped: {err}")
            return
        failed += bad
        mult = f"{box / cost:.1f}".replace(".", ",") if box else "-"   # Buy Box / purchase price
        print(f"{raw:<13} {asin:<10} {eur(cost):>10} {eur(box):>10} {mult:>5} {amazon:<6} "
              f"{est if est is not None else '-':>6}  {note}".rstrip())


if __name__ == "__main__":
    main()

Output (illustrative data: a retried 502, a billed 404, a duplicate, two EANs for one ASIN and four rows skipped before paying)

amazon.de (A1PA6795UKMFR9): converter + statistics + estimated sales, at most 3 credits per EAN

ean           asin         EK netto    Buy Box  x EK amz30d est/mo  note
4012345000016 B0DECHRG01     9,80 €    24,99 €   2,5 yes       340
4012345000023 B0DEMUEHL2    12,40 €    32,90 €   2,7 no         85
4.00638E+12   skipped: Excel turned the EAN into a number, the last digits are lost
4012345000030 -              7,15 €  no match on amazon.de (billed 404)
4012345000016 skipped: duplicate row (a second check bills up to 3 more credits)
4012345000047 B0DECHRG01    17,90 €  same ASIN as 4012345000016, not checked twice
4012345000054 B0DEBECHR5     6,20 €          -     - ?           -  nobody holds the Buy Box, estimate skipped
4012345000062 skipped: not a valid EAN (check digit), the converter would bill it
4012345000078 skipped: purchase price '1.249' is ambiguous or not a euro amount
  • x EK divides the Buy Box by the net purchase price. The Buy Box is what a buyer pays, VAT and shipping included, and Amazon's fees still come off it, so read it as a first filter, not a margin.
  • amz30d yes comes from shareBuyBox false: Amazon (A3JWKAKR8XB7XF) held the Buy Box at some point in the last 30 days. ? means the holder history could not be read, not "no".
  • 4012345000047 is a two-pack whose EAN points to the same ASIN as the single item, which happens when one listing carries several EANs. The script pays for the conversion and reuses the first row instead of buying statistics twice.
  • 4.00638E+12 is an EAN that Excel stored as a number; the last digits are gone, so the script skips it rather than paying for a guess. Format the EAN column as text before you export.
  • est/mo is a model estimate of monthly units, not a measurement. Treat 340 and 85 as an order of magnitude.
Terminal-theme sequence of the three calls the script makes for one EAN on amazon.de, and the single billed call when the converter answers 404
Three billed calls per EAN; a converter 404 ends the row after one.

Credits per EAN on amazon.de

1 credit per request, the same as on every store. The script spends 3 credits for a full row, 2 when nobody holds the Buy Box (the estimate is skipped), and 1 when the converter answers a billed 404 or the ASIN was already checked. Skipped rows cost 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 every time. The example run made 11 calls for the 5 EANs it sent: 2 full rows, 1 retried 502, 1 converter 404, 1 repeated ASIN and 1 row without a Buy Box, so 11 credits. Gate errors such as a missing parameter cost nothing. Plans and credit packs are on the pricing page. For a deeper supplier analysis, see the wholesale price list guide and UPC and EAN to ASIN.

Can I use German category names for amazon.de bestsellers?

Yes. category_id on /amazon-bestsellers takes a numeric browse node, a top-level slug such as electronics or toys, or a category name as amazon.de shows it, in German. amazon.de's tree has 51 top-level categories and 32,456 nodes ("electronics" is "Elektronik & Foto"). A name match adds resolved_category to the response, with the ID, name and path the API used. A name that fits several categories ("Kopfhörer" matches two) or none, and an unknown numeric ID, get a free 400; a name error lists the closest matches when there are any. An English name such as "dog food" finds nothing on amazon.de. Check the path before you trust the list: "Ladegeräte" resolves to chargers under Auto & Motorrad, not phone chargers, so pass the numeric ID when you know it. The category explorer shows the tree.

The resolved_category field of /amazon-bestsellers with category_id=Kaffeemühlen on amazon.de

{
  "resolved_category": {
    "category_id": "3424591",
    "name": "Kaffeemühlen",
    "path": "Küche, Haushalt & Wohnen > Küche, Kochen & Backen > Kaffee, Tee & Espresso > Kaffeemühlen"
  }
}

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

amazon.de answers in German, so productInfo.title, bulletPoints, lookup's category names and the bestseller tree come back in German. Some fields are normalised for you: offer conditions such as "Neu" or "Gebraucht - Wie neu" arrive as "New" and "Used - Like New", delivery words like "morgen" become a deliveryDate, and search marks results labelled "Gesponsert" as sponsored: true. Lookup's listedSinceDate works on amazon.de: it reads the "Im Angebot von Amazon.de seit" row (for example "12. März 2021") and returns 2021-03-12, unlike stores whose date label the lookup does not recognise. That date is when the listing was created, not necessarily when it first shipped.

Frequently Asked Questions

What is the Amazon Germany marketplace ID?

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

Does the Amazon Germany API include price history?

Yes. amazon.de 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.

Can I look up amazon.de products by EAN?

Yes. Call /amazon-asin-converter with conversion_direction=ean-to-asin and the barcode in asin. It returns the first matching ASIN. An unknown barcode is a billed 404, so check the EAN's check digit before you send it.

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

A3JWKAKR8XB7XF. 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.de.

Do bestseller category names have to be German on amazon.de?

Yes. A name is matched against amazon.de's German tree, so "Kaffeemühlen" works and "dog food" gets a free 400 with no match. Top-level slugs such as electronics and numeric IDs work as well.

Bottom line: use A1PA6795UKMFR9 for amazon.de, divide statistics prices by 100, round the offers Buy Box, and send German category names. Because amazon.de has history coverage, a barcode list becomes Buy Box, Amazon presence and a sales estimate in three calls per EAN. 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