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.
| Item | amazon.de |
|---|---|
| Marketplace ID | A1PA6795UKMFR9 |
| Store | amazon.de |
| Currency | EUR, currencySymbol "€" (Euro) |
| Default postcode | 10115 (Berlin), used when geo_location is not sent |
| Amazon's own seller ID | A3JWKAKR8XB7XF |
| History endpoints | answer: statistics, estimated sales, ASIN converter |
| listedSinceDate (lookup) | filled from "Im Angebot von Amazon.de seit" |
| Page language | German: titles, bullets and category names |
| Bestseller category tree | amazon.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.

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.
| Endpoint | Field | Unit | Example |
|---|---|---|---|
| /amazon-product-lookup | productInfo.buyBoxInfo.price | decimal euros, item only | 24.99 or "N/A" |
| /amazon-product-offers | buyBox.totalPrice | decimal euros, incl. shipping | 24.99 (round it) |
| /amazon-product-statistics | buyBoxPrice | integer euro cents, incl. shipping | 2499 or "N/A" |
| /amazon-product-statistics | stats.buyBoxPriceHistory | [date, cents] pairs | ["2026-10-01", 2499] |
| /amazon-search | listingPrice.price.total | string, 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
shareBuyBoxfalse: 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.

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.